From b7ea3b17dc6f66e3299bb0d20ce28f13da4d4abd Mon Sep 17 00:00:00 2001 From: ocavue Date: Sun, 17 May 2026 05:06:31 +1000 Subject: [PATCH 1/3] chore: clean up outdated examples --- lit-block-handle/.gitignore | 4 - lit-block-handle/README.md | 15 - lit-block-handle/index.html | 13 - lit-block-handle/package.json | 24 - lit-block-handle/src/app.css | 12 - lit-block-handle/src/app.ts | 18 - .../editor/examples/block-handle/editor.ts | 99 --- .../editor/examples/block-handle/extension.ts | 10 - .../editor/examples/block-handle/index.ts | 1 - .../editor/sample/sample-doc-block-handle.ts | 323 -------- .../editor/ui/block-handle/block-handle.ts | 77 -- .../editor/ui/block-handle/index.ts | 1 - .../ui/code-block-view/code-block-view.ts | 106 --- .../editor/ui/code-block-view/index.ts | 1 - .../ui/drop-indicator/drop-indicator.ts | 43 -- .../editor/ui/drop-indicator/index.ts | 1 - .../components/editor/ui/editor-context.ts | 6 - lit-block-handle/src/editor.ts | 18 - lit-block-handle/tsconfig.json | 25 - lit-block-handle/vite.config.ts | 6 - lit-code-block/.gitignore | 4 - lit-code-block/README.md | 15 - lit-code-block/index.html | 13 - lit-code-block/package.json | 24 - lit-code-block/src/app.css | 12 - lit-code-block/src/app.ts | 18 - .../editor/examples/code-block/editor.ts | 87 --- .../editor/examples/code-block/extension.ts | 24 - .../editor/examples/code-block/index.ts | 1 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../editor/sample/sample-uploader.ts | 54 -- .../src/components/editor/ui/button/button.ts | 92 --- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.ts | 106 --- .../editor/ui/code-block-view/index.ts | 1 - .../components/editor/ui/editor-context.ts | 6 - .../image-upload-popover.ts | 200 ----- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.ts | 467 ------------ lit-code-block/src/editor.ts | 18 - lit-code-block/tsconfig.json | 25 - lit-code-block/vite.config.ts | 6 - lit-minimal/.gitignore | 4 - lit-minimal/README.md | 15 - lit-minimal/index.html | 13 - lit-minimal/package.json | 24 - lit-minimal/src/app.css | 12 - lit-minimal/src/app.ts | 18 - .../editor/examples/minimal/editor.ts | 64 -- .../editor/examples/minimal/index.ts | 1 - lit-minimal/src/editor.ts | 18 - lit-minimal/tsconfig.json | 25 - lit-minimal/vite.config.ts | 6 - lit-slash-menu/.gitignore | 4 - lit-slash-menu/README.md | 15 - lit-slash-menu/index.html | 13 - lit-slash-menu/package.json | 25 - lit-slash-menu/src/app.css | 12 - lit-slash-menu/src/app.ts | 18 - .../editor/examples/slash-menu/editor.ts | 86 --- .../editor/examples/slash-menu/extension.ts | 12 - .../editor/examples/slash-menu/index.ts | 1 - .../components/editor/ui/editor-context.ts | 6 - .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.ts | 17 - .../editor/ui/slash-menu/slash-menu-item.ts | 44 -- .../editor/ui/slash-menu/slash-menu.ts | 147 ---- lit-slash-menu/src/editor.ts | 18 - lit-slash-menu/tsconfig.json | 25 - lit-slash-menu/vite.config.ts | 6 - lit-table/.gitignore | 4 - lit-table/README.md | 15 - lit-table/index.html | 13 - lit-table/package.json | 25 - lit-table/src/app.css | 12 - lit-table/src/app.ts | 18 - .../editor/examples/table/editor.ts | 96 --- .../editor/examples/table/extension.ts | 20 - .../components/editor/examples/table/index.ts | 1 - .../editor/sample/sample-doc-table.ts | 174 ----- .../components/editor/ui/editor-context.ts | 6 - .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.ts | 335 --------- lit-table/src/editor.ts | 18 - lit-table/tsconfig.json | 25 - lit-table/vite.config.ts | 6 - lit-toolbar/.gitignore | 4 - lit-toolbar/README.md | 15 - lit-toolbar/index.html | 13 - lit-toolbar/package.json | 25 - lit-toolbar/src/app.css | 12 - lit-toolbar/src/app.ts | 18 - .../editor/examples/toolbar/editor.ts | 85 --- .../editor/examples/toolbar/extension.ts | 8 - .../editor/examples/toolbar/index.ts | 1 - .../editor/sample/sample-uploader.ts | 54 -- .../src/components/editor/ui/button/button.ts | 92 --- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/editor-context.ts | 6 - .../image-upload-popover.ts | 200 ----- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.ts | 467 ------------ lit-toolbar/src/editor.ts | 18 - lit-toolbar/tsconfig.json | 25 - lit-toolbar/vite.config.ts | 6 - next-full/.gitignore | 4 - next-full/README.md | 15 - next-full/app/app.css | 12 - next-full/app/layout.tsx | 22 - next-full/app/page.tsx | 9 - next-full/components/editor-dynamic.tsx | 15 - .../editor/examples/full/editor.tsx | 56 -- .../editor/examples/full/extension.ts | 34 - .../components/editor/examples/full/html.ts | 35 - .../components/editor/examples/full/index.ts | 2 - next-full/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-full.ts | 442 ----------- .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/sample/sample-user-data.ts | 54 -- .../editor/ui/block-handle/block-handle.tsx | 33 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.tsx | 46 -- .../components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 39 - .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.tsx | 7 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../editor/ui/image-view/image-view.tsx | 94 --- .../components/editor/ui/image-view/index.ts | 14 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 11 - .../editor/ui/slash-menu/slash-menu-item.tsx | 23 - .../editor/ui/slash-menu/slash-menu.tsx | 102 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 188 ----- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.tsx | 54 -- .../components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 64 -- next-full/next.config.mjs | 4 - next-full/package.json | 29 - next-full/postcss.config.mjs | 8 - next-full/tsconfig.json | 33 - nuxt-full/.gitignore | 4 - nuxt-full/README.md | 15 - nuxt-full/nuxt.config.ts | 12 - nuxt-full/package.json | 27 - nuxt-full/src/app.css | 12 - nuxt-full/src/app.vue | 12 - .../editor/examples/full/editor.vue | 53 -- .../editor/examples/full/extension.ts | 34 - .../components/editor/examples/full/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-full.ts | 442 ----------- .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/sample/sample-user-data.ts | 54 -- .../editor/ui/block-handle/block-handle.vue | 39 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.vue | 41 -- .../editor/ui/code-block-view/index.ts | 12 - .../ui/drop-indicator/drop-indicator.vue | 7 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../editor/ui/image-view/image-view.vue | 97 --- .../components/editor/ui/image-view/index.ts | 11 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.vue | 219 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.vue | 11 - .../editor/ui/slash-menu/slash-menu-item.vue | 24 - .../editor/ui/slash-menu/slash-menu.vue | 106 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.vue | 204 ------ .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.vue | 59 -- .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.vue | 74 -- nuxt-full/src/editor.vue | 7 - nuxt-full/tsconfig.json | 4 - preact-block-handle/.gitignore | 4 - preact-block-handle/README.md | 15 - preact-block-handle/index.html | 12 - preact-block-handle/package.json | 25 - preact-block-handle/src/App.tsx | 5 - preact-block-handle/src/app.css | 12 - .../editor/examples/block-handle/editor.tsx | 39 - .../editor/examples/block-handle/extension.ts | 10 - .../editor/examples/block-handle/index.ts | 1 - .../editor/sample/sample-doc-block-handle.ts | 323 -------- .../editor/ui/block-handle/block-handle.tsx | 31 - .../editor/ui/block-handle/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 42 -- .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.tsx | 5 - .../editor/ui/drop-indicator/index.ts | 1 - preact-block-handle/src/main.tsx | 5 - preact-block-handle/tsconfig.app.json | 33 - preact-block-handle/tsconfig.json | 7 - preact-block-handle/tsconfig.node.json | 26 - preact-block-handle/vite.config.ts | 8 - preact-blockquote/.gitignore | 4 - preact-blockquote/README.md | 15 - preact-blockquote/index.html | 12 - preact-blockquote/package.json | 25 - preact-blockquote/src/App.tsx | 5 - preact-blockquote/src/app.css | 12 - .../editor/examples/blockquote/editor.tsx | 30 - .../editor/examples/blockquote/extension.ts | 17 - .../editor/examples/blockquote/index.ts | 1 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-blockquote/src/main.tsx | 5 - preact-blockquote/tsconfig.app.json | 33 - preact-blockquote/tsconfig.json | 7 - preact-blockquote/tsconfig.node.json | 26 - preact-blockquote/vite.config.ts | 8 - preact-bold/.gitignore | 4 - preact-bold/README.md | 15 - preact-bold/index.html | 12 - preact-bold/package.json | 25 - preact-bold/src/App.tsx | 5 - preact-bold/src/app.css | 12 - .../editor/examples/bold/editor.tsx | 37 - .../editor/examples/bold/extension.ts | 17 - .../components/editor/examples/bold/index.ts | 1 - .../editor/sample/sample-doc-bold.ts | 44 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-bold/src/main.tsx | 5 - preact-bold/tsconfig.app.json | 33 - preact-bold/tsconfig.json | 7 - preact-bold/tsconfig.node.json | 26 - preact-bold/vite.config.ts | 8 - preact-change-tracking/.gitignore | 4 - preact-change-tracking/README.md | 15 - preact-change-tracking/index.html | 12 - preact-change-tracking/package.json | 25 - preact-change-tracking/src/App.tsx | 5 - preact-change-tracking/src/app.css | 12 - .../examples/change-tracking/editor-diff.tsx | 30 - .../examples/change-tracking/editor-main.tsx | 37 - .../examples/change-tracking/editor.tsx | 78 -- .../editor/examples/change-tracking/index.ts | 1 - preact-change-tracking/src/main.tsx | 5 - preact-change-tracking/tsconfig.app.json | 33 - preact-change-tracking/tsconfig.json | 7 - preact-change-tracking/tsconfig.node.json | 26 - preact-change-tracking/vite.config.ts | 8 - preact-code-block-themes/.gitignore | 4 - preact-code-block-themes/README.md | 15 - preact-code-block-themes/index.html | 12 - preact-code-block-themes/package.json | 25 - preact-code-block-themes/src/App.tsx | 5 - preact-code-block-themes/src/app.css | 12 - .../examples/code-block-themes/editor.tsx | 37 - .../examples/code-block-themes/extension.ts | 10 - .../examples/code-block-themes/index.ts | 1 - .../code-block-themes/theme-selector.tsx | 38 - .../examples/code-block-themes/toolbar.tsx | 9 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../ui/code-block-view/code-block-view.tsx | 42 -- .../editor/ui/code-block-view/index.ts | 15 - preact-code-block-themes/src/main.tsx | 5 - preact-code-block-themes/tsconfig.app.json | 33 - preact-code-block-themes/tsconfig.json | 7 - preact-code-block-themes/tsconfig.node.json | 26 - preact-code-block-themes/vite.config.ts | 8 - preact-code-block/.gitignore | 4 - preact-code-block/README.md | 15 - preact-code-block/index.html | 12 - preact-code-block/package.json | 25 - preact-code-block/src/App.tsx | 5 - preact-code-block/src/app.css | 12 - .../editor/examples/code-block/editor.tsx | 37 - .../editor/examples/code-block/extension.ts | 24 - .../editor/examples/code-block/index.ts | 1 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 42 -- .../editor/ui/code-block-view/index.ts | 15 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-code-block/src/main.tsx | 5 - preact-code-block/tsconfig.app.json | 33 - preact-code-block/tsconfig.json | 7 - preact-code-block/tsconfig.node.json | 26 - preact-code-block/vite.config.ts | 8 - preact-code/.gitignore | 4 - preact-code/README.md | 15 - preact-code/index.html | 12 - preact-code/package.json | 25 - preact-code/src/App.tsx | 5 - preact-code/src/app.css | 12 - .../editor/examples/code/editor.tsx | 37 - .../editor/examples/code/extension.ts | 17 - .../components/editor/examples/code/index.ts | 1 - .../editor/sample/sample-doc-code.ts | 30 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-code/src/main.tsx | 5 - preact-code/tsconfig.app.json | 33 - preact-code/tsconfig.json | 7 - preact-code/tsconfig.node.json | 26 - preact-code/vite.config.ts | 8 - preact-drop-cursor/.gitignore | 4 - preact-drop-cursor/README.md | 15 - preact-drop-cursor/index.html | 12 - preact-drop-cursor/package.json | 25 - preact-drop-cursor/src/App.tsx | 5 - preact-drop-cursor/src/app.css | 12 - .../editor/examples/drop-cursor/editor.tsx | 35 - .../editor/examples/drop-cursor/extension.ts | 23 - .../editor/examples/drop-cursor/index.ts | 1 - .../editor/sample/sample-doc-drop-cursor.ts | 40 - preact-drop-cursor/src/main.tsx | 5 - preact-drop-cursor/tsconfig.app.json | 33 - preact-drop-cursor/tsconfig.json | 7 - preact-drop-cursor/tsconfig.node.json | 26 - preact-drop-cursor/vite.config.ts | 8 - preact-emoji-rules/.gitignore | 4 - preact-emoji-rules/README.md | 15 - preact-emoji-rules/index.html | 12 - preact-emoji-rules/package.json | 25 - preact-emoji-rules/src/App.tsx | 5 - preact-emoji-rules/src/app.css | 12 - .../editor/examples/emoji-rules/editor.tsx | 28 - .../editor/examples/emoji-rules/emoji.ts | 15 - .../editor/examples/emoji-rules/extension.ts | 15 - .../editor/examples/emoji-rules/index.ts | 1 - preact-emoji-rules/src/main.tsx | 5 - preact-emoji-rules/tsconfig.app.json | 33 - preact-emoji-rules/tsconfig.json | 7 - preact-emoji-rules/tsconfig.node.json | 26 - preact-emoji-rules/vite.config.ts | 8 - preact-full/.gitignore | 4 - preact-full/README.md | 15 - preact-full/index.html | 12 - preact-full/package.json | 26 - preact-full/src/App.tsx | 5 - preact-full/src/app.css | 12 - .../editor/examples/full/editor.tsx | 54 -- .../editor/examples/full/extension.ts | 34 - .../components/editor/examples/full/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-full.ts | 442 ----------- .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/sample/sample-user-data.ts | 54 -- .../editor/ui/block-handle/block-handle.tsx | 31 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 42 -- .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.tsx | 5 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../editor/ui/image-view/image-view.tsx | 95 --- .../components/editor/ui/image-view/index.ts | 14 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 9 - .../editor/ui/slash-menu/slash-menu-item.tsx | 21 - .../editor/ui/slash-menu/slash-menu.tsx | 100 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 186 ----- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.tsx | 52 -- .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 62 -- preact-full/src/main.tsx | 5 - preact-full/tsconfig.app.json | 33 - preact-full/tsconfig.json | 7 - preact-full/tsconfig.node.json | 26 - preact-full/vite.config.ts | 8 - preact-gap-cursor/.gitignore | 4 - preact-gap-cursor/README.md | 15 - preact-gap-cursor/index.html | 12 - preact-gap-cursor/package.json | 25 - preact-gap-cursor/src/App.tsx | 5 - preact-gap-cursor/src/app.css | 12 - .../editor/examples/gap-cursor/editor.tsx | 34 - .../editor/examples/gap-cursor/extension.ts | 19 - .../editor/examples/gap-cursor/index.ts | 1 - .../editor/sample/sample-doc-gap-cursor.ts | 28 - preact-gap-cursor/src/main.tsx | 5 - preact-gap-cursor/tsconfig.app.json | 33 - preact-gap-cursor/tsconfig.json | 7 - preact-gap-cursor/tsconfig.node.json | 26 - preact-gap-cursor/vite.config.ts | 8 - preact-hard-break/.gitignore | 4 - preact-hard-break/README.md | 15 - preact-hard-break/index.html | 12 - preact-hard-break/package.json | 25 - preact-hard-break/src/App.tsx | 5 - preact-hard-break/src/app.css | 12 - .../editor/examples/hard-break/editor.tsx | 37 - .../editor/examples/hard-break/extension.ts | 17 - .../editor/examples/hard-break/index.ts | 1 - .../editor/examples/hard-break/toolbar.tsx | 31 - .../editor/sample/sample-doc-hard-break.ts | 68 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - preact-hard-break/src/main.tsx | 5 - preact-hard-break/tsconfig.app.json | 33 - preact-hard-break/tsconfig.json | 7 - preact-hard-break/tsconfig.node.json | 26 - preact-hard-break/vite.config.ts | 8 - preact-heading/.gitignore | 4 - preact-heading/README.md | 15 - preact-heading/index.html | 12 - preact-heading/package.json | 25 - preact-heading/src/App.tsx | 5 - preact-heading/src/app.css | 12 - .../editor/examples/heading/editor.tsx | 36 - .../editor/examples/heading/extension.ts | 17 - .../editor/examples/heading/index.ts | 1 - .../editor/sample/sample-doc-heading.ts | 23 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-heading/src/main.tsx | 5 - preact-heading/tsconfig.app.json | 33 - preact-heading/tsconfig.json | 7 - preact-heading/tsconfig.node.json | 26 - preact-heading/vite.config.ts | 8 - preact-highlight/.gitignore | 4 - preact-highlight/README.md | 15 - preact-highlight/index.html | 12 - preact-highlight/package.json | 25 - preact-highlight/src/App.tsx | 5 - preact-highlight/src/app.css | 12 - .../editor/examples/highlight/editor.tsx | 37 - .../editor/examples/highlight/extension.ts | 17 - .../editor/examples/highlight/index.ts | 1 - .../editor/examples/highlight/toolbar.tsx | 32 - .../editor/sample/sample-doc-highlight.ts | 30 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - preact-highlight/src/main.tsx | 5 - preact-highlight/tsconfig.app.json | 33 - preact-highlight/tsconfig.json | 7 - preact-highlight/tsconfig.node.json | 26 - preact-highlight/vite.config.ts | 8 - preact-horizontal-rule/.gitignore | 4 - preact-horizontal-rule/README.md | 15 - preact-horizontal-rule/index.html | 12 - preact-horizontal-rule/package.json | 25 - preact-horizontal-rule/src/App.tsx | 5 - preact-horizontal-rule/src/app.css | 12 - .../examples/horizontal-rule/editor.tsx | 30 - .../examples/horizontal-rule/extension.ts | 17 - .../editor/examples/horizontal-rule/index.ts | 1 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-horizontal-rule/src/main.tsx | 5 - preact-horizontal-rule/tsconfig.app.json | 33 - preact-horizontal-rule/tsconfig.json | 7 - preact-horizontal-rule/tsconfig.node.json | 26 - preact-horizontal-rule/vite.config.ts | 8 - preact-image-view/.gitignore | 4 - preact-image-view/README.md | 15 - preact-image-view/index.html | 12 - preact-image-view/package.json | 25 - preact-image-view/src/App.tsx | 5 - preact-image-view/src/app.css | 12 - .../editor/examples/image-view/editor.tsx | 35 - .../editor/examples/image-view/extension.ts | 18 - .../editor/examples/image-view/index.ts | 1 - .../editor/sample/sample-doc-image.ts | 32 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/image-view/image-view.tsx | 95 --- .../components/editor/ui/image-view/index.ts | 14 - preact-image-view/src/main.tsx | 5 - preact-image-view/tsconfig.app.json | 33 - preact-image-view/tsconfig.json | 7 - preact-image-view/tsconfig.node.json | 26 - preact-image-view/vite.config.ts | 8 - preact-inline-menu/.gitignore | 4 - preact-inline-menu/README.md | 15 - preact-inline-menu/index.html | 12 - preact-inline-menu/package.json | 25 - preact-inline-menu/src/App.tsx | 5 - preact-inline-menu/src/app.css | 12 - .../editor/examples/inline-menu/editor.tsx | 36 - .../editor/examples/inline-menu/extension.ts | 7 - .../editor/examples/inline-menu/index.ts | 1 - .../editor/sample/sample-doc-inline-menu.ts | 33 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ preact-inline-menu/src/main.tsx | 5 - preact-inline-menu/tsconfig.app.json | 33 - preact-inline-menu/tsconfig.json | 7 - preact-inline-menu/tsconfig.node.json | 26 - preact-inline-menu/vite.config.ts | 8 - preact-italic/.gitignore | 4 - preact-italic/README.md | 15 - preact-italic/index.html | 12 - preact-italic/package.json | 25 - preact-italic/src/App.tsx | 5 - preact-italic/src/app.css | 12 - .../editor/examples/italic/editor.tsx | 37 - .../editor/examples/italic/extension.ts | 17 - .../editor/examples/italic/index.ts | 1 - .../editor/sample/sample-doc-italic.ts | 44 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-italic/src/main.tsx | 5 - preact-italic/tsconfig.app.json | 33 - preact-italic/tsconfig.json | 7 - preact-italic/tsconfig.node.json | 26 - preact-italic/vite.config.ts | 8 - preact-katex/.gitignore | 4 - preact-katex/README.md | 15 - preact-katex/index.html | 12 - preact-katex/package.json | 26 - preact-katex/src/App.tsx | 5 - preact-katex/src/app.css | 12 - .../editor/examples/katex/editor.tsx | 35 - .../editor/examples/katex/extension.ts | 17 - .../components/editor/examples/katex/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-tex.ts | 60 -- preact-katex/src/main.tsx | 5 - preact-katex/tsconfig.app.json | 33 - preact-katex/tsconfig.json | 7 - preact-katex/tsconfig.node.json | 26 - preact-katex/vite.config.ts | 8 - preact-keymap/.gitignore | 4 - preact-keymap/README.md | 15 - preact-keymap/index.html | 12 - preact-keymap/package.json | 25 - preact-keymap/src/App.tsx | 5 - preact-keymap/src/app.css | 12 - .../editor/examples/keymap/editor.tsx | 52 -- .../editor/examples/keymap/extension.ts | 8 - .../editor/examples/keymap/index.ts | 1 - .../editor/examples/keymap/toolbar.tsx | 27 - .../examples/keymap/use-submit-keymap.ts | 19 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - preact-keymap/src/main.tsx | 5 - preact-keymap/tsconfig.app.json | 33 - preact-keymap/tsconfig.json | 7 - preact-keymap/tsconfig.node.json | 26 - preact-keymap/vite.config.ts | 8 - preact-link-mark-view/.gitignore | 4 - preact-link-mark-view/README.md | 15 - preact-link-mark-view/index.html | 12 - preact-link-mark-view/package.json | 25 - preact-link-mark-view/src/App.tsx | 5 - preact-link-mark-view/src/app.css | 12 - .../editor/examples/link-mark-view/editor.tsx | 35 - .../examples/link-mark-view/extension.ts | 17 - .../editor/examples/link-mark-view/index.ts | 1 - .../examples/link-mark-view/link-view.tsx | 45 -- .../sample/sample-doc-link-mark-view.ts | 30 - preact-link-mark-view/src/main.tsx | 5 - preact-link-mark-view/tsconfig.app.json | 33 - preact-link-mark-view/tsconfig.json | 7 - preact-link-mark-view/tsconfig.node.json | 26 - preact-link-mark-view/vite.config.ts | 8 - preact-link/.gitignore | 4 - preact-link/README.md | 15 - preact-link/index.html | 12 - preact-link/package.json | 25 - preact-link/src/App.tsx | 5 - preact-link/src/app.css | 12 - .../editor/examples/link/editor.tsx | 37 - .../editor/examples/link/extension.ts | 17 - .../components/editor/examples/link/index.ts | 1 - .../editor/sample/sample-doc-link.ts | 30 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ preact-link/src/main.tsx | 5 - preact-link/tsconfig.app.json | 33 - preact-link/tsconfig.json | 7 - preact-link/tsconfig.node.json | 26 - preact-link/vite.config.ts | 8 - preact-list-custom-checkbox/.gitignore | 4 - preact-list-custom-checkbox/README.md | 15 - preact-list-custom-checkbox/index.html | 12 - preact-list-custom-checkbox/package.json | 25 - preact-list-custom-checkbox/src/App.tsx | 5 - preact-list-custom-checkbox/src/app.css | 12 - .../list-custom-checkbox/custom-list.css | 75 -- .../examples/list-custom-checkbox/editor.tsx | 44 -- .../list-custom-checkbox/extension.ts | 8 - .../examples/list-custom-checkbox/index.ts | 1 - .../sample/sample-doc-list-custom-checkbox.ts | 38 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-list-custom-checkbox/src/main.tsx | 5 - preact-list-custom-checkbox/tsconfig.app.json | 33 - preact-list-custom-checkbox/tsconfig.json | 7 - .../tsconfig.node.json | 26 - preact-list-custom-checkbox/vite.config.ts | 8 - preact-list/.gitignore | 4 - preact-list/README.md | 15 - preact-list/index.html | 12 - preact-list/package.json | 25 - preact-list/src/App.tsx | 5 - preact-list/src/app.css | 12 - .../editor/examples/list/editor.tsx | 37 - .../editor/examples/list/extension.ts | 17 - .../components/editor/examples/list/index.ts | 1 - .../editor/sample/sample-doc-list.ts | 47 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-list/src/main.tsx | 5 - preact-list/tsconfig.app.json | 33 - preact-list/tsconfig.json | 7 - preact-list/tsconfig.node.json | 26 - preact-list/vite.config.ts | 8 - preact-loro/.gitignore | 4 - preact-loro/README.md | 15 - preact-loro/index.html | 12 - preact-loro/package.json | 28 - preact-loro/src/App.tsx | 5 - preact-loro/src/app.css | 12 - .../editor/examples/loro/editor-component.tsx | 36 - .../editor/examples/loro/editor.tsx | 63 -- .../editor/examples/loro/extension.ts | 47 -- .../components/editor/examples/loro/index.ts | 1 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-loro/src/main.tsx | 5 - preact-loro/tsconfig.app.json | 33 - preact-loro/tsconfig.json | 7 - preact-loro/tsconfig.node.json | 26 - preact-loro/vite.config.ts | 9 - preact-mark-rule/.gitignore | 4 - preact-mark-rule/README.md | 15 - preact-mark-rule/index.html | 12 - preact-mark-rule/package.json | 25 - preact-mark-rule/src/App.tsx | 5 - preact-mark-rule/src/app.css | 12 - .../editor/examples/mark-rule/editor.tsx | 28 - .../editor/examples/mark-rule/extension.ts | 32 - .../editor/examples/mark-rule/index.ts | 1 - .../editor/examples/mark-rule/issue-link.ts | 32 - preact-mark-rule/src/main.tsx | 5 - preact-mark-rule/tsconfig.app.json | 33 - preact-mark-rule/tsconfig.json | 7 - preact-mark-rule/tsconfig.node.json | 26 - preact-mark-rule/vite.config.ts | 8 - preact-minimal/.gitignore | 4 - preact-minimal/README.md | 15 - preact-minimal/index.html | 12 - preact-minimal/package.json | 25 - preact-minimal/src/App.tsx | 5 - preact-minimal/src/app.css | 12 - .../editor/examples/minimal/editor.tsx | 20 - .../editor/examples/minimal/index.ts | 1 - preact-minimal/src/main.tsx | 5 - preact-minimal/tsconfig.app.json | 33 - preact-minimal/tsconfig.json | 7 - preact-minimal/tsconfig.node.json | 26 - preact-minimal/vite.config.ts | 8 - preact-placeholder/.gitignore | 4 - preact-placeholder/README.md | 15 - preact-placeholder/index.html | 12 - preact-placeholder/package.json | 25 - preact-placeholder/src/App.tsx | 5 - preact-placeholder/src/app.css | 12 - .../editor/examples/placeholder/editor.tsx | 39 - .../editor/examples/placeholder/extension.ts | 12 - .../editor/examples/placeholder/index.ts | 1 - preact-placeholder/src/main.tsx | 5 - preact-placeholder/tsconfig.app.json | 33 - preact-placeholder/tsconfig.json | 7 - preact-placeholder/tsconfig.node.json | 26 - preact-placeholder/vite.config.ts | 8 - preact-readonly/.gitignore | 4 - preact-readonly/README.md | 15 - preact-readonly/index.html | 12 - preact-readonly/package.json | 25 - preact-readonly/src/App.tsx | 5 - preact-readonly/src/app.css | 12 - .../editor/examples/readonly/editor.tsx | 37 - .../editor/examples/readonly/extension.ts | 7 - .../editor/examples/readonly/index.ts | 1 - .../editor/examples/readonly/toolbar.tsx | 19 - .../editor/examples/readonly/use-readonly.ts | 14 - .../editor/sample/sample-doc-readonly.ts | 16 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - preact-readonly/src/main.tsx | 5 - preact-readonly/tsconfig.app.json | 33 - preact-readonly/tsconfig.json | 7 - preact-readonly/tsconfig.node.json | 26 - preact-readonly/vite.config.ts | 8 - preact-rtl/.gitignore | 4 - preact-rtl/README.md | 15 - preact-rtl/index.html | 12 - preact-rtl/package.json | 25 - preact-rtl/src/App.tsx | 5 - preact-rtl/src/app.css | 12 - .../components/editor/examples/rtl/editor.tsx | 50 -- .../components/editor/examples/rtl/index.ts | 1 - .../editor/sample/sample-doc-rtl.ts | 187 ----- .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/block-handle/block-handle.tsx | 31 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/drop-indicator/drop-indicator.tsx | 5 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 9 - .../editor/ui/slash-menu/slash-menu-item.tsx | 21 - .../editor/ui/slash-menu/slash-menu.tsx | 100 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 186 ----- .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-rtl/src/main.tsx | 5 - preact-rtl/tsconfig.app.json | 33 - preact-rtl/tsconfig.json | 7 - preact-rtl/tsconfig.node.json | 26 - preact-rtl/vite.config.ts | 8 - preact-save-html/.gitignore | 4 - preact-save-html/README.md | 15 - preact-save-html/index.html | 12 - preact-save-html/package.json | 25 - preact-save-html/src/App.tsx | 5 - preact-save-html/src/app.css | 12 - .../editor/examples/save-html/editor.tsx | 74 -- .../editor/examples/save-html/index.ts | 1 - preact-save-html/src/main.tsx | 5 - preact-save-html/tsconfig.app.json | 33 - preact-save-html/tsconfig.json | 7 - preact-save-html/tsconfig.node.json | 26 - preact-save-html/vite.config.ts | 8 - preact-save-json/.gitignore | 4 - preact-save-json/README.md | 15 - preact-save-json/index.html | 12 - preact-save-json/package.json | 25 - preact-save-json/src/App.tsx | 5 - preact-save-json/src/app.css | 12 - .../editor/examples/save-json/editor.tsx | 74 -- .../editor/examples/save-json/index.ts | 1 - preact-save-json/src/main.tsx | 5 - preact-save-json/tsconfig.app.json | 33 - preact-save-json/tsconfig.json | 7 - preact-save-json/tsconfig.node.json | 26 - preact-save-json/vite.config.ts | 8 - preact-save-markdown/.gitignore | 4 - preact-save-markdown/README.md | 15 - preact-save-markdown/index.html | 12 - preact-save-markdown/package.json | 32 - preact-save-markdown/src/App.tsx | 5 - preact-save-markdown/src/app.css | 12 - .../editor/examples/save-markdown/editor.tsx | 78 -- .../editor/examples/save-markdown/index.ts | 1 - .../editor/examples/save-markdown/markdown.ts | 26 - preact-save-markdown/src/main.tsx | 5 - preact-save-markdown/tsconfig.app.json | 33 - preact-save-markdown/tsconfig.json | 7 - preact-save-markdown/tsconfig.node.json | 26 - preact-save-markdown/vite.config.ts | 8 - preact-search/.gitignore | 4 - preact-search/README.md | 15 - preact-search/index.html | 12 - preact-search/package.json | 25 - preact-search/src/App.tsx | 5 - preact-search/src/app.css | 12 - .../editor/examples/search/editor.tsx | 41 -- .../editor/examples/search/extension.ts | 9 - .../editor/examples/search/index.ts | 1 - .../editor/sample/sample-doc-search.ts | 79 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../src/components/editor/ui/search/index.ts | 1 - .../components/editor/ui/search/search.tsx | 167 ----- preact-search/src/main.tsx | 5 - preact-search/tsconfig.app.json | 33 - preact-search/tsconfig.json | 7 - preact-search/tsconfig.node.json | 26 - preact-search/vite.config.ts | 8 - preact-slash-menu/.gitignore | 4 - preact-slash-menu/README.md | 15 - preact-slash-menu/index.html | 12 - preact-slash-menu/package.json | 25 - preact-slash-menu/src/App.tsx | 5 - preact-slash-menu/src/app.css | 12 - .../editor/examples/slash-menu/editor.tsx | 31 - .../editor/examples/slash-menu/extension.ts | 12 - .../editor/examples/slash-menu/index.ts | 1 - .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 9 - .../editor/ui/slash-menu/slash-menu-item.tsx | 21 - .../editor/ui/slash-menu/slash-menu.tsx | 100 --- preact-slash-menu/src/main.tsx | 5 - preact-slash-menu/tsconfig.app.json | 33 - preact-slash-menu/tsconfig.json | 7 - preact-slash-menu/tsconfig.node.json | 26 - preact-slash-menu/vite.config.ts | 8 - preact-strike/.gitignore | 4 - preact-strike/README.md | 15 - preact-strike/index.html | 12 - preact-strike/package.json | 25 - preact-strike/src/App.tsx | 5 - preact-strike/src/app.css | 12 - .../editor/examples/strike/editor.tsx | 37 - .../editor/examples/strike/extension.ts | 17 - .../editor/examples/strike/index.ts | 1 - .../editor/examples/strike/toolbar.tsx | 32 - .../editor/sample/sample-doc-strike.ts | 30 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - preact-strike/src/main.tsx | 5 - preact-strike/tsconfig.app.json | 33 - preact-strike/tsconfig.json | 7 - preact-strike/tsconfig.node.json | 26 - preact-strike/vite.config.ts | 8 - preact-sub-sup/.gitignore | 4 - preact-sub-sup/README.md | 15 - preact-sub-sup/index.html | 12 - preact-sub-sup/package.json | 25 - preact-sub-sup/src/App.tsx | 5 - preact-sub-sup/src/app.css | 12 - .../editor/examples/sub-sup/editor.tsx | 37 - .../editor/examples/sub-sup/extension.ts | 32 - .../editor/examples/sub-sup/index.ts | 1 - .../editor/examples/sub-sup/toolbar.tsx | 44 -- .../editor/sample/sample-doc-sub-sup.ts | 42 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - preact-sub-sup/src/main.tsx | 5 - preact-sub-sup/tsconfig.app.json | 33 - preact-sub-sup/tsconfig.json | 7 - preact-sub-sup/tsconfig.node.json | 26 - preact-sub-sup/vite.config.ts | 8 - preact-table/.gitignore | 4 - preact-table/README.md | 15 - preact-table/index.html | 12 - preact-table/package.json | 25 - preact-table/src/App.tsx | 5 - preact-table/src/app.css | 12 - .../editor/examples/table/editor.tsx | 37 - .../editor/examples/table/extension.ts | 20 - .../components/editor/examples/table/index.ts | 1 - .../editor/sample/sample-doc-table.ts | 174 ----- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 186 ----- preact-table/src/main.tsx | 5 - preact-table/tsconfig.app.json | 33 - preact-table/tsconfig.json | 7 - preact-table/tsconfig.node.json | 26 - preact-table/vite.config.ts | 8 - preact-temml/.gitignore | 4 - preact-temml/README.md | 15 - preact-temml/index.html | 12 - preact-temml/package.json | 26 - preact-temml/src/App.tsx | 5 - preact-temml/src/app.css | 12 - .../editor/examples/temml/editor.tsx | 35 - .../editor/examples/temml/extension.ts | 17 - .../components/editor/examples/temml/index.ts | 1 - .../editor/sample/sample-doc-tex.ts | 60 -- .../src/components/editor/sample/temml.ts | 17 - preact-temml/src/main.tsx | 5 - preact-temml/tsconfig.app.json | 33 - preact-temml/tsconfig.json | 7 - preact-temml/tsconfig.node.json | 26 - preact-temml/vite.config.ts | 8 - preact-text-align/.gitignore | 4 - preact-text-align/README.md | 15 - preact-text-align/index.html | 12 - preact-text-align/package.json | 25 - preact-text-align/src/App.tsx | 5 - preact-text-align/src/app.css | 12 - .../editor/examples/text-align/editor.tsx | 37 - .../editor/examples/text-align/extension.ts | 12 - .../editor/examples/text-align/index.ts | 1 - .../editor/examples/text-align/toolbar.tsx | 78 -- .../editor/sample/sample-doc-text-align.ts | 56 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - preact-text-align/src/main.tsx | 5 - preact-text-align/tsconfig.app.json | 33 - preact-text-align/tsconfig.json | 7 - preact-text-align/tsconfig.node.json | 26 - preact-text-align/vite.config.ts | 8 - preact-text-color/.gitignore | 4 - preact-text-color/README.md | 15 - preact-text-color/index.html | 12 - preact-text-color/package.json | 25 - preact-text-color/src/App.tsx | 5 - preact-text-color/src/app.css | 12 - .../editor/examples/text-color/editor.tsx | 37 - .../editor/examples/text-color/extension.ts | 14 - .../editor/examples/text-color/index.ts | 1 - .../examples/text-color/inline-menu.tsx | 145 ---- .../editor/sample/sample-doc-text-color.ts | 120 --- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - preact-text-color/src/main.tsx | 5 - preact-text-color/tsconfig.app.json | 33 - preact-text-color/tsconfig.json | 7 - preact-text-color/tsconfig.node.json | 26 - preact-text-color/vite.config.ts | 8 - preact-toolbar/.gitignore | 4 - preact-toolbar/README.md | 15 - preact-toolbar/index.html | 12 - preact-toolbar/package.json | 25 - preact-toolbar/src/App.tsx | 5 - preact-toolbar/src/app.css | 12 - .../editor/examples/toolbar/editor.tsx | 32 - .../editor/examples/toolbar/extension.ts | 8 - .../editor/examples/toolbar/index.ts | 1 - .../editor/sample/sample-uploader.ts | 54 -- .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-toolbar/src/main.tsx | 5 - preact-toolbar/tsconfig.app.json | 33 - preact-toolbar/tsconfig.json | 7 - preact-toolbar/tsconfig.node.json | 26 - preact-toolbar/vite.config.ts | 8 - preact-typography/.gitignore | 4 - preact-typography/README.md | 15 - preact-typography/index.html | 12 - preact-typography/package.json | 26 - preact-typography/src/App.tsx | 5 - preact-typography/src/app.css | 12 - .../editor/examples/typography/editor.tsx | 39 - .../editor/examples/typography/extension.ts | 17 - .../editor/examples/typography/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-typography.ts | 693 ------------------ .../editor/ui/block-handle/block-handle.tsx | 31 - .../editor/ui/block-handle/index.ts | 1 - .../ui/drop-indicator/drop-indicator.tsx | 5 - .../editor/ui/drop-indicator/index.ts | 1 - preact-typography/src/main.tsx | 5 - preact-typography/tsconfig.app.json | 33 - preact-typography/tsconfig.json | 7 - preact-typography/tsconfig.node.json | 26 - preact-typography/vite.config.ts | 8 - preact-underline/.gitignore | 4 - preact-underline/README.md | 15 - preact-underline/index.html | 12 - preact-underline/package.json | 25 - preact-underline/src/App.tsx | 5 - preact-underline/src/app.css | 12 - .../editor/examples/underline/editor.tsx | 37 - .../editor/examples/underline/extension.ts | 17 - .../editor/examples/underline/index.ts | 1 - .../editor/sample/sample-doc-underline.ts | 30 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-underline/src/main.tsx | 5 - preact-underline/tsconfig.app.json | 33 - preact-underline/tsconfig.json | 7 - preact-underline/tsconfig.node.json | 26 - preact-underline/vite.config.ts | 8 - preact-unmount/.gitignore | 4 - preact-unmount/README.md | 15 - preact-unmount/index.html | 12 - preact-unmount/package.json | 25 - preact-unmount/src/App.tsx | 5 - preact-unmount/src/app.css | 12 - .../examples/unmount/editor-component.tsx | 32 - .../editor/examples/unmount/editor.tsx | 44 -- .../examples/unmount/extension-component.tsx | 14 - .../editor/examples/unmount/index.ts | 1 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ preact-unmount/src/main.tsx | 5 - preact-unmount/tsconfig.app.json | 33 - preact-unmount/tsconfig.json | 7 - preact-unmount/tsconfig.node.json | 26 - preact-unmount/vite.config.ts | 8 - preact-user-menu-dynamic/.gitignore | 4 - preact-user-menu-dynamic/README.md | 15 - preact-user-menu-dynamic/index.html | 12 - preact-user-menu-dynamic/package.json | 25 - preact-user-menu-dynamic/src/App.tsx | 5 - preact-user-menu-dynamic/src/app.css | 12 - .../examples/user-menu-dynamic/editor.tsx | 30 - .../examples/user-menu-dynamic/extension.ts | 16 - .../examples/user-menu-dynamic/index.ts | 1 - .../user-menu-dynamic/use-user-query.ts | 40 - .../user-menu-dynamic/user-menu-dynamic.tsx | 21 - .../editor/sample/sample-query-users.ts | 40 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 62 -- preact-user-menu-dynamic/src/main.tsx | 5 - preact-user-menu-dynamic/tsconfig.app.json | 33 - preact-user-menu-dynamic/tsconfig.json | 7 - preact-user-menu-dynamic/tsconfig.node.json | 26 - preact-user-menu-dynamic/vite.config.ts | 8 - preact-user-menu/.gitignore | 4 - preact-user-menu/README.md | 15 - preact-user-menu/index.html | 12 - preact-user-menu/package.json | 25 - preact-user-menu/src/App.tsx | 5 - preact-user-menu/src/app.css | 12 - .../editor/examples/user-menu/editor.tsx | 35 - .../editor/examples/user-menu/extension.ts | 16 - .../editor/examples/user-menu/index.ts | 1 - .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.tsx | 52 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 62 -- preact-user-menu/src/main.tsx | 5 - preact-user-menu/tsconfig.app.json | 33 - preact-user-menu/tsconfig.json | 7 - preact-user-menu/tsconfig.node.json | 26 - preact-user-menu/vite.config.ts | 8 - preact-word-counter/.gitignore | 4 - preact-word-counter/README.md | 15 - preact-word-counter/index.html | 12 - preact-word-counter/package.json | 25 - preact-word-counter/src/App.tsx | 5 - preact-word-counter/src/app.css | 12 - .../editor/examples/word-counter/editor.tsx | 40 - .../editor/examples/word-counter/extension.ts | 8 - .../editor/examples/word-counter/index.ts | 1 - .../editor/sample/sample-doc-word-counter.ts | 16 - .../editor/ui/word-counter/index.ts | 1 - .../editor/ui/word-counter/word-counter.tsx | 22 - preact-word-counter/src/main.tsx | 5 - preact-word-counter/tsconfig.app.json | 33 - preact-word-counter/tsconfig.json | 7 - preact-word-counter/tsconfig.node.json | 26 - preact-word-counter/vite.config.ts | 8 - preact-yjs/.gitignore | 4 - preact-yjs/README.md | 15 - preact-yjs/index.html | 12 - preact-yjs/package.json | 29 - preact-yjs/src/App.tsx | 5 - preact-yjs/src/app.css | 12 - .../editor/examples/yjs/editor-component.tsx | 41 -- .../components/editor/examples/yjs/editor.tsx | 16 - .../editor/examples/yjs/extension.ts | 48 -- .../components/editor/examples/yjs/index.ts | 1 - .../components/editor/ui/button/button.tsx | 44 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 144 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 363 --------- preact-yjs/src/main.tsx | 5 - preact-yjs/tsconfig.app.json | 33 - preact-yjs/tsconfig.json | 7 - preact-yjs/tsconfig.node.json | 26 - preact-yjs/vite.config.ts | 8 - react-block-handle/.gitignore | 4 - react-block-handle/README.md | 15 - react-block-handle/index.html | 12 - react-block-handle/package.json | 28 - react-block-handle/src/App.tsx | 5 - react-block-handle/src/app.css | 12 - .../editor/examples/block-handle/editor.tsx | 41 -- .../editor/examples/block-handle/extension.ts | 10 - .../editor/examples/block-handle/index.ts | 1 - .../editor/sample/sample-doc-block-handle.ts | 323 -------- .../editor/ui/block-handle/block-handle.tsx | 33 - .../editor/ui/block-handle/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 39 - .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.tsx | 7 - .../editor/ui/drop-indicator/index.ts | 1 - react-block-handle/src/main.tsx | 10 - react-block-handle/tsconfig.app.json | 28 - react-block-handle/tsconfig.json | 7 - react-block-handle/tsconfig.node.json | 26 - react-block-handle/vite.config.ts | 8 - react-blockquote/.gitignore | 4 - react-blockquote/README.md | 15 - react-blockquote/index.html | 12 - react-blockquote/package.json | 28 - react-blockquote/src/App.tsx | 5 - react-blockquote/src/app.css | 12 - .../editor/examples/blockquote/editor.tsx | 32 - .../editor/examples/blockquote/extension.ts | 17 - .../editor/examples/blockquote/index.ts | 1 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-blockquote/src/main.tsx | 10 - react-blockquote/tsconfig.app.json | 28 - react-blockquote/tsconfig.json | 7 - react-blockquote/tsconfig.node.json | 26 - react-blockquote/vite.config.ts | 8 - react-bold/.gitignore | 4 - react-bold/README.md | 15 - react-bold/index.html | 12 - react-bold/package.json | 28 - react-bold/src/App.tsx | 5 - react-bold/src/app.css | 12 - .../editor/examples/bold/editor.tsx | 39 - .../editor/examples/bold/extension.ts | 17 - .../components/editor/examples/bold/index.ts | 1 - .../editor/sample/sample-doc-bold.ts | 44 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-bold/src/main.tsx | 10 - react-bold/tsconfig.app.json | 28 - react-bold/tsconfig.json | 7 - react-bold/tsconfig.node.json | 26 - react-bold/vite.config.ts | 8 - react-change-tracking/.gitignore | 4 - react-change-tracking/README.md | 15 - react-change-tracking/index.html | 12 - react-change-tracking/package.json | 28 - react-change-tracking/src/App.tsx | 5 - react-change-tracking/src/app.css | 12 - .../examples/change-tracking/editor-diff.tsx | 32 - .../examples/change-tracking/editor-main.tsx | 39 - .../examples/change-tracking/editor.tsx | 80 -- .../editor/examples/change-tracking/index.ts | 1 - react-change-tracking/src/main.tsx | 10 - react-change-tracking/tsconfig.app.json | 28 - react-change-tracking/tsconfig.json | 7 - react-change-tracking/tsconfig.node.json | 26 - react-change-tracking/vite.config.ts | 8 - react-code-block-themes/.gitignore | 4 - react-code-block-themes/README.md | 15 - react-code-block-themes/index.html | 12 - react-code-block-themes/package.json | 28 - react-code-block-themes/src/App.tsx | 5 - react-code-block-themes/src/app.css | 12 - .../examples/code-block-themes/editor.tsx | 39 - .../examples/code-block-themes/extension.ts | 10 - .../examples/code-block-themes/index.ts | 1 - .../code-block-themes/theme-selector.tsx | 35 - .../examples/code-block-themes/toolbar.tsx | 11 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../ui/code-block-view/code-block-view.tsx | 39 - .../editor/ui/code-block-view/index.ts | 15 - react-code-block-themes/src/main.tsx | 10 - react-code-block-themes/tsconfig.app.json | 28 - react-code-block-themes/tsconfig.json | 7 - react-code-block-themes/tsconfig.node.json | 26 - react-code-block-themes/vite.config.ts | 8 - react-code-block/.gitignore | 4 - react-code-block/README.md | 15 - react-code-block/index.html | 12 - react-code-block/package.json | 28 - react-code-block/src/App.tsx | 5 - react-code-block/src/app.css | 12 - .../editor/examples/code-block/editor.tsx | 39 - .../editor/examples/code-block/extension.ts | 24 - .../editor/examples/code-block/index.ts | 1 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 39 - .../editor/ui/code-block-view/index.ts | 15 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-code-block/src/main.tsx | 10 - react-code-block/tsconfig.app.json | 28 - react-code-block/tsconfig.json | 7 - react-code-block/tsconfig.node.json | 26 - react-code-block/vite.config.ts | 8 - react-code/.gitignore | 4 - react-code/README.md | 15 - react-code/index.html | 12 - react-code/package.json | 28 - react-code/src/App.tsx | 5 - react-code/src/app.css | 12 - .../editor/examples/code/editor.tsx | 39 - .../editor/examples/code/extension.ts | 17 - .../components/editor/examples/code/index.ts | 1 - .../editor/sample/sample-doc-code.ts | 30 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-code/src/main.tsx | 10 - react-code/tsconfig.app.json | 28 - react-code/tsconfig.json | 7 - react-code/tsconfig.node.json | 26 - react-code/vite.config.ts | 8 - react-drop-cursor/.gitignore | 4 - react-drop-cursor/README.md | 15 - react-drop-cursor/index.html | 12 - react-drop-cursor/package.json | 28 - react-drop-cursor/src/App.tsx | 5 - react-drop-cursor/src/app.css | 12 - .../editor/examples/drop-cursor/editor.tsx | 37 - .../editor/examples/drop-cursor/extension.ts | 23 - .../editor/examples/drop-cursor/index.ts | 1 - .../editor/sample/sample-doc-drop-cursor.ts | 40 - react-drop-cursor/src/main.tsx | 10 - react-drop-cursor/tsconfig.app.json | 28 - react-drop-cursor/tsconfig.json | 7 - react-drop-cursor/tsconfig.node.json | 26 - react-drop-cursor/vite.config.ts | 8 - react-emoji-rules/.gitignore | 4 - react-emoji-rules/README.md | 15 - react-emoji-rules/index.html | 12 - react-emoji-rules/package.json | 28 - react-emoji-rules/src/App.tsx | 5 - react-emoji-rules/src/app.css | 12 - .../editor/examples/emoji-rules/editor.tsx | 30 - .../editor/examples/emoji-rules/emoji.ts | 15 - .../editor/examples/emoji-rules/extension.ts | 15 - .../editor/examples/emoji-rules/index.ts | 1 - react-emoji-rules/src/main.tsx | 10 - react-emoji-rules/tsconfig.app.json | 28 - react-emoji-rules/tsconfig.json | 7 - react-emoji-rules/tsconfig.node.json | 26 - react-emoji-rules/vite.config.ts | 8 - react-full/.gitignore | 4 - react-full/README.md | 15 - react-full/index.html | 12 - react-full/package.json | 29 - react-full/src/App.tsx | 5 - react-full/src/app.css | 12 - .../editor/examples/full/editor.tsx | 56 -- .../editor/examples/full/extension.ts | 34 - .../components/editor/examples/full/html.ts | 35 - .../components/editor/examples/full/index.ts | 2 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-full.ts | 442 ----------- .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/sample/sample-user-data.ts | 54 -- .../editor/ui/block-handle/block-handle.tsx | 33 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 39 - .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.tsx | 7 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../editor/ui/image-view/image-view.tsx | 94 --- .../components/editor/ui/image-view/index.ts | 14 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 11 - .../editor/ui/slash-menu/slash-menu-item.tsx | 23 - .../editor/ui/slash-menu/slash-menu.tsx | 102 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 188 ----- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.tsx | 54 -- .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 64 -- react-full/src/main.tsx | 10 - react-full/tsconfig.app.json | 28 - react-full/tsconfig.json | 7 - react-full/tsconfig.node.json | 26 - react-full/vite.config.ts | 8 - react-gap-cursor/.gitignore | 4 - react-gap-cursor/README.md | 15 - react-gap-cursor/index.html | 12 - react-gap-cursor/package.json | 28 - react-gap-cursor/src/App.tsx | 5 - react-gap-cursor/src/app.css | 12 - .../editor/examples/gap-cursor/editor.tsx | 36 - .../editor/examples/gap-cursor/extension.ts | 19 - .../editor/examples/gap-cursor/index.ts | 1 - .../editor/sample/sample-doc-gap-cursor.ts | 28 - react-gap-cursor/src/main.tsx | 10 - react-gap-cursor/tsconfig.app.json | 28 - react-gap-cursor/tsconfig.json | 7 - react-gap-cursor/tsconfig.node.json | 26 - react-gap-cursor/vite.config.ts | 8 - react-hard-break/.gitignore | 4 - react-hard-break/README.md | 15 - react-hard-break/index.html | 12 - react-hard-break/package.json | 28 - react-hard-break/src/App.tsx | 5 - react-hard-break/src/app.css | 12 - .../editor/examples/hard-break/editor.tsx | 39 - .../editor/examples/hard-break/extension.ts | 17 - .../editor/examples/hard-break/index.ts | 1 - .../editor/examples/hard-break/toolbar.tsx | 33 - .../editor/sample/sample-doc-hard-break.ts | 68 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - react-hard-break/src/main.tsx | 10 - react-hard-break/tsconfig.app.json | 28 - react-hard-break/tsconfig.json | 7 - react-hard-break/tsconfig.node.json | 26 - react-hard-break/vite.config.ts | 8 - react-heading/.gitignore | 4 - react-heading/README.md | 15 - react-heading/index.html | 12 - react-heading/package.json | 28 - react-heading/src/App.tsx | 5 - react-heading/src/app.css | 12 - .../editor/examples/heading/editor.tsx | 38 - .../editor/examples/heading/extension.ts | 17 - .../editor/examples/heading/index.ts | 1 - .../editor/sample/sample-doc-heading.ts | 23 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-heading/src/main.tsx | 10 - react-heading/tsconfig.app.json | 28 - react-heading/tsconfig.json | 7 - react-heading/tsconfig.node.json | 26 - react-heading/vite.config.ts | 8 - react-highlight/.gitignore | 4 - react-highlight/README.md | 15 - react-highlight/index.html | 12 - react-highlight/package.json | 28 - react-highlight/src/App.tsx | 5 - react-highlight/src/app.css | 12 - .../editor/examples/highlight/editor.tsx | 39 - .../editor/examples/highlight/extension.ts | 17 - .../editor/examples/highlight/index.ts | 1 - .../editor/examples/highlight/toolbar.tsx | 34 - .../editor/sample/sample-doc-highlight.ts | 30 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - react-highlight/src/main.tsx | 10 - react-highlight/tsconfig.app.json | 28 - react-highlight/tsconfig.json | 7 - react-highlight/tsconfig.node.json | 26 - react-highlight/vite.config.ts | 8 - react-horizontal-rule/.gitignore | 4 - react-horizontal-rule/README.md | 15 - react-horizontal-rule/index.html | 12 - react-horizontal-rule/package.json | 28 - react-horizontal-rule/src/App.tsx | 5 - react-horizontal-rule/src/app.css | 12 - .../examples/horizontal-rule/editor.tsx | 32 - .../examples/horizontal-rule/extension.ts | 17 - .../editor/examples/horizontal-rule/index.ts | 1 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-horizontal-rule/src/main.tsx | 10 - react-horizontal-rule/tsconfig.app.json | 28 - react-horizontal-rule/tsconfig.json | 7 - react-horizontal-rule/tsconfig.node.json | 26 - react-horizontal-rule/vite.config.ts | 8 - react-image-view/.gitignore | 4 - react-image-view/README.md | 15 - react-image-view/index.html | 12 - react-image-view/package.json | 28 - react-image-view/src/App.tsx | 5 - react-image-view/src/app.css | 12 - .../editor/examples/image-view/editor.tsx | 37 - .../editor/examples/image-view/extension.ts | 18 - .../editor/examples/image-view/index.ts | 1 - .../editor/sample/sample-doc-image.ts | 32 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/image-view/image-view.tsx | 94 --- .../components/editor/ui/image-view/index.ts | 14 - react-image-view/src/main.tsx | 10 - react-image-view/tsconfig.app.json | 28 - react-image-view/tsconfig.json | 7 - react-image-view/tsconfig.node.json | 26 - react-image-view/vite.config.ts | 8 - react-inline-menu/.gitignore | 4 - react-inline-menu/README.md | 15 - react-inline-menu/index.html | 12 - react-inline-menu/package.json | 28 - react-inline-menu/src/App.tsx | 5 - react-inline-menu/src/app.css | 12 - .../editor/examples/inline-menu/editor.tsx | 38 - .../editor/examples/inline-menu/extension.ts | 7 - .../editor/examples/inline-menu/index.ts | 1 - .../editor/sample/sample-doc-inline-menu.ts | 33 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ react-inline-menu/src/main.tsx | 10 - react-inline-menu/tsconfig.app.json | 28 - react-inline-menu/tsconfig.json | 7 - react-inline-menu/tsconfig.node.json | 26 - react-inline-menu/vite.config.ts | 8 - react-italic/.gitignore | 4 - react-italic/README.md | 15 - react-italic/index.html | 12 - react-italic/package.json | 28 - react-italic/src/App.tsx | 5 - react-italic/src/app.css | 12 - .../editor/examples/italic/editor.tsx | 39 - .../editor/examples/italic/extension.ts | 17 - .../editor/examples/italic/index.ts | 1 - .../editor/sample/sample-doc-italic.ts | 44 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-italic/src/main.tsx | 10 - react-italic/tsconfig.app.json | 28 - react-italic/tsconfig.json | 7 - react-italic/tsconfig.node.json | 26 - react-italic/vite.config.ts | 8 - react-katex/.gitignore | 4 - react-katex/README.md | 15 - react-katex/index.html | 12 - react-katex/package.json | 29 - react-katex/src/App.tsx | 5 - react-katex/src/app.css | 12 - .../editor/examples/katex/editor.tsx | 37 - .../editor/examples/katex/extension.ts | 17 - .../components/editor/examples/katex/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-tex.ts | 60 -- react-katex/src/main.tsx | 10 - react-katex/tsconfig.app.json | 28 - react-katex/tsconfig.json | 7 - react-katex/tsconfig.node.json | 26 - react-katex/vite.config.ts | 8 - react-keymap/.gitignore | 4 - react-keymap/README.md | 15 - react-keymap/index.html | 12 - react-keymap/package.json | 28 - react-keymap/src/App.tsx | 5 - react-keymap/src/app.css | 12 - .../editor/examples/keymap/editor.tsx | 54 -- .../editor/examples/keymap/extension.ts | 8 - .../editor/examples/keymap/index.ts | 1 - .../editor/examples/keymap/toolbar.tsx | 29 - .../examples/keymap/use-submit-keymap.ts | 19 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - react-keymap/src/main.tsx | 10 - react-keymap/tsconfig.app.json | 28 - react-keymap/tsconfig.json | 7 - react-keymap/tsconfig.node.json | 26 - react-keymap/vite.config.ts | 8 - react-link-mark-view/.gitignore | 4 - react-link-mark-view/README.md | 15 - react-link-mark-view/index.html | 12 - react-link-mark-view/package.json | 28 - react-link-mark-view/src/App.tsx | 5 - react-link-mark-view/src/app.css | 12 - .../editor/examples/link-mark-view/editor.tsx | 37 - .../examples/link-mark-view/extension.ts | 17 - .../editor/examples/link-mark-view/index.ts | 1 - .../examples/link-mark-view/link-view.tsx | 47 -- .../sample/sample-doc-link-mark-view.ts | 30 - react-link-mark-view/src/main.tsx | 10 - react-link-mark-view/tsconfig.app.json | 28 - react-link-mark-view/tsconfig.json | 7 - react-link-mark-view/tsconfig.node.json | 26 - react-link-mark-view/vite.config.ts | 8 - react-link/.gitignore | 4 - react-link/README.md | 15 - react-link/index.html | 12 - react-link/package.json | 28 - react-link/src/App.tsx | 5 - react-link/src/app.css | 12 - .../editor/examples/link/editor.tsx | 39 - .../editor/examples/link/extension.ts | 17 - .../components/editor/examples/link/index.ts | 1 - .../editor/sample/sample-doc-link.ts | 30 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ react-link/src/main.tsx | 10 - react-link/tsconfig.app.json | 28 - react-link/tsconfig.json | 7 - react-link/tsconfig.node.json | 26 - react-link/vite.config.ts | 8 - react-list-custom-checkbox/.gitignore | 4 - react-list-custom-checkbox/README.md | 15 - react-list-custom-checkbox/index.html | 12 - react-list-custom-checkbox/package.json | 28 - react-list-custom-checkbox/src/App.tsx | 5 - react-list-custom-checkbox/src/app.css | 12 - .../list-custom-checkbox/custom-list.css | 75 -- .../examples/list-custom-checkbox/editor.tsx | 46 -- .../list-custom-checkbox/extension.ts | 8 - .../examples/list-custom-checkbox/index.ts | 1 - .../sample/sample-doc-list-custom-checkbox.ts | 38 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-list-custom-checkbox/src/main.tsx | 10 - react-list-custom-checkbox/tsconfig.app.json | 28 - react-list-custom-checkbox/tsconfig.json | 7 - react-list-custom-checkbox/tsconfig.node.json | 26 - react-list-custom-checkbox/vite.config.ts | 8 - react-list/.gitignore | 4 - react-list/README.md | 15 - react-list/index.html | 12 - react-list/package.json | 28 - react-list/src/App.tsx | 5 - react-list/src/app.css | 12 - .../editor/examples/list/editor.tsx | 39 - .../editor/examples/list/extension.ts | 17 - .../components/editor/examples/list/index.ts | 1 - .../editor/sample/sample-doc-list.ts | 47 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-list/src/main.tsx | 10 - react-list/tsconfig.app.json | 28 - react-list/tsconfig.json | 7 - react-list/tsconfig.node.json | 26 - react-list/vite.config.ts | 8 - react-loro/.gitignore | 4 - react-loro/README.md | 15 - react-loro/index.html | 12 - react-loro/package.json | 31 - react-loro/src/App.tsx | 5 - react-loro/src/app.css | 12 - .../editor/examples/loro/editor-component.tsx | 38 - .../editor/examples/loro/editor.tsx | 65 -- .../editor/examples/loro/extension.ts | 47 -- .../components/editor/examples/loro/index.ts | 1 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-loro/src/main.tsx | 10 - react-loro/tsconfig.app.json | 28 - react-loro/tsconfig.json | 7 - react-loro/tsconfig.node.json | 26 - react-loro/vite.config.ts | 9 - react-mark-rule/.gitignore | 4 - react-mark-rule/README.md | 15 - react-mark-rule/index.html | 12 - react-mark-rule/package.json | 28 - react-mark-rule/src/App.tsx | 5 - react-mark-rule/src/app.css | 12 - .../editor/examples/mark-rule/editor.tsx | 30 - .../editor/examples/mark-rule/extension.ts | 32 - .../editor/examples/mark-rule/index.ts | 1 - .../editor/examples/mark-rule/issue-link.ts | 32 - react-mark-rule/src/main.tsx | 10 - react-mark-rule/tsconfig.app.json | 28 - react-mark-rule/tsconfig.json | 7 - react-mark-rule/tsconfig.node.json | 26 - react-mark-rule/vite.config.ts | 8 - react-minimal/.gitignore | 4 - react-minimal/README.md | 15 - react-minimal/index.html | 12 - react-minimal/package.json | 28 - react-minimal/src/App.tsx | 5 - react-minimal/src/app.css | 12 - .../editor/examples/minimal/editor.tsx | 22 - .../editor/examples/minimal/index.ts | 1 - react-minimal/src/main.tsx | 10 - react-minimal/tsconfig.app.json | 28 - react-minimal/tsconfig.json | 7 - react-minimal/tsconfig.node.json | 26 - react-minimal/vite.config.ts | 8 - react-page/.gitignore | 4 - react-page/README.md | 15 - react-page/index.html | 12 - react-page/package.json | 28 - react-page/src/App.tsx | 5 - react-page/src/app.css | 12 - .../editor/examples/page/editor.tsx | 49 -- .../editor/examples/page/extension.ts | 9 - .../components/editor/examples/page/index.ts | 1 - .../editor/examples/page/paper-controller.tsx | 142 ---- .../components/editor/examples/page/zoom.css | 9 - .../editor/sample/sample-doc-page.ts | 98 --- react-page/src/main.tsx | 10 - react-page/tsconfig.app.json | 28 - react-page/tsconfig.json | 7 - react-page/tsconfig.node.json | 26 - react-page/vite.config.ts | 8 - react-placeholder/.gitignore | 4 - react-placeholder/README.md | 15 - react-placeholder/index.html | 12 - react-placeholder/package.json | 28 - react-placeholder/src/App.tsx | 5 - react-placeholder/src/app.css | 12 - .../editor/examples/placeholder/editor.tsx | 41 -- .../editor/examples/placeholder/extension.ts | 12 - .../editor/examples/placeholder/index.ts | 1 - react-placeholder/src/main.tsx | 10 - react-placeholder/tsconfig.app.json | 28 - react-placeholder/tsconfig.json | 7 - react-placeholder/tsconfig.node.json | 26 - react-placeholder/vite.config.ts | 8 - react-readonly/.gitignore | 4 - react-readonly/README.md | 15 - react-readonly/index.html | 12 - react-readonly/package.json | 28 - react-readonly/src/App.tsx | 5 - react-readonly/src/app.css | 12 - .../editor/examples/readonly/editor.tsx | 39 - .../editor/examples/readonly/extension.ts | 7 - .../editor/examples/readonly/index.ts | 1 - .../editor/examples/readonly/toolbar.tsx | 21 - .../editor/examples/readonly/use-readonly.ts | 14 - .../editor/sample/sample-doc-readonly.ts | 16 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - react-readonly/src/main.tsx | 10 - react-readonly/tsconfig.app.json | 28 - react-readonly/tsconfig.json | 7 - react-readonly/tsconfig.node.json | 26 - react-readonly/vite.config.ts | 8 - react-rtl/.gitignore | 4 - react-rtl/README.md | 15 - react-rtl/index.html | 12 - react-rtl/package.json | 28 - react-rtl/src/App.tsx | 5 - react-rtl/src/app.css | 12 - .../components/editor/examples/rtl/editor.tsx | 52 -- .../components/editor/examples/rtl/index.ts | 1 - .../editor/sample/sample-doc-rtl.ts | 187 ----- .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/block-handle/block-handle.tsx | 33 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/drop-indicator/drop-indicator.tsx | 7 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 11 - .../editor/ui/slash-menu/slash-menu-item.tsx | 23 - .../editor/ui/slash-menu/slash-menu.tsx | 102 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 188 ----- .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-rtl/src/main.tsx | 10 - react-rtl/tsconfig.app.json | 28 - react-rtl/tsconfig.json | 7 - react-rtl/tsconfig.node.json | 26 - react-rtl/vite.config.ts | 8 - react-save-html/.gitignore | 4 - react-save-html/README.md | 15 - react-save-html/index.html | 12 - react-save-html/package.json | 28 - react-save-html/src/App.tsx | 5 - react-save-html/src/app.css | 12 - .../editor/examples/save-html/editor.tsx | 76 -- .../editor/examples/save-html/index.ts | 1 - react-save-html/src/main.tsx | 10 - react-save-html/tsconfig.app.json | 28 - react-save-html/tsconfig.json | 7 - react-save-html/tsconfig.node.json | 26 - react-save-html/vite.config.ts | 8 - react-save-json/.gitignore | 4 - react-save-json/README.md | 15 - react-save-json/index.html | 12 - react-save-json/package.json | 28 - react-save-json/src/App.tsx | 5 - react-save-json/src/app.css | 12 - .../editor/examples/save-json/editor.tsx | 76 -- .../editor/examples/save-json/index.ts | 1 - react-save-json/src/main.tsx | 10 - react-save-json/tsconfig.app.json | 28 - react-save-json/tsconfig.json | 7 - react-save-json/tsconfig.node.json | 26 - react-save-json/vite.config.ts | 8 - react-save-markdown/.gitignore | 4 - react-save-markdown/README.md | 15 - react-save-markdown/index.html | 12 - react-save-markdown/package.json | 35 - react-save-markdown/src/App.tsx | 5 - react-save-markdown/src/app.css | 12 - .../editor/examples/save-markdown/editor.tsx | 80 -- .../editor/examples/save-markdown/index.ts | 1 - .../editor/examples/save-markdown/markdown.ts | 26 - react-save-markdown/src/main.tsx | 10 - react-save-markdown/tsconfig.app.json | 28 - react-save-markdown/tsconfig.json | 7 - react-save-markdown/tsconfig.node.json | 26 - react-save-markdown/vite.config.ts | 8 - react-search/.gitignore | 4 - react-search/README.md | 15 - react-search/index.html | 12 - react-search/package.json | 28 - react-search/src/App.tsx | 5 - react-search/src/app.css | 12 - .../editor/examples/search/editor.tsx | 43 -- .../editor/examples/search/extension.ts | 9 - .../editor/examples/search/index.ts | 1 - .../editor/sample/sample-doc-search.ts | 79 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../src/components/editor/ui/search/index.ts | 1 - .../components/editor/ui/search/search.tsx | 169 ----- react-search/src/main.tsx | 10 - react-search/tsconfig.app.json | 28 - react-search/tsconfig.json | 7 - react-search/tsconfig.node.json | 26 - react-search/vite.config.ts | 8 - react-slash-menu/.gitignore | 4 - react-slash-menu/README.md | 15 - react-slash-menu/index.html | 12 - react-slash-menu/package.json | 28 - react-slash-menu/src/App.tsx | 5 - react-slash-menu/src/app.css | 12 - .../editor/examples/slash-menu/editor.tsx | 33 - .../editor/examples/slash-menu/extension.ts | 12 - .../editor/examples/slash-menu/index.ts | 1 - .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 11 - .../editor/ui/slash-menu/slash-menu-item.tsx | 23 - .../editor/ui/slash-menu/slash-menu.tsx | 102 --- react-slash-menu/src/main.tsx | 10 - react-slash-menu/tsconfig.app.json | 28 - react-slash-menu/tsconfig.json | 7 - react-slash-menu/tsconfig.node.json | 26 - react-slash-menu/vite.config.ts | 8 - react-strike/.gitignore | 4 - react-strike/README.md | 15 - react-strike/index.html | 12 - react-strike/package.json | 28 - react-strike/src/App.tsx | 5 - react-strike/src/app.css | 12 - .../editor/examples/strike/editor.tsx | 39 - .../editor/examples/strike/extension.ts | 17 - .../editor/examples/strike/index.ts | 1 - .../editor/examples/strike/toolbar.tsx | 34 - .../editor/sample/sample-doc-strike.ts | 30 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - react-strike/src/main.tsx | 10 - react-strike/tsconfig.app.json | 28 - react-strike/tsconfig.json | 7 - react-strike/tsconfig.node.json | 26 - react-strike/vite.config.ts | 8 - react-sub-sup/.gitignore | 4 - react-sub-sup/README.md | 15 - react-sub-sup/index.html | 12 - react-sub-sup/package.json | 28 - react-sub-sup/src/App.tsx | 5 - react-sub-sup/src/app.css | 12 - .../editor/examples/sub-sup/editor.tsx | 39 - .../editor/examples/sub-sup/extension.ts | 32 - .../editor/examples/sub-sup/index.ts | 1 - .../editor/examples/sub-sup/toolbar.tsx | 46 -- .../editor/sample/sample-doc-sub-sup.ts | 42 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - react-sub-sup/src/main.tsx | 10 - react-sub-sup/tsconfig.app.json | 28 - react-sub-sup/tsconfig.json | 7 - react-sub-sup/tsconfig.node.json | 26 - react-sub-sup/vite.config.ts | 8 - react-table/.gitignore | 4 - react-table/README.md | 15 - react-table/index.html | 12 - react-table/package.json | 28 - react-table/src/App.tsx | 5 - react-table/src/app.css | 12 - .../editor/examples/table/editor.tsx | 39 - .../editor/examples/table/extension.ts | 20 - .../components/editor/examples/table/index.ts | 1 - .../editor/sample/sample-doc-table.ts | 174 ----- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 188 ----- react-table/src/main.tsx | 10 - react-table/tsconfig.app.json | 28 - react-table/tsconfig.json | 7 - react-table/tsconfig.node.json | 26 - react-table/vite.config.ts | 8 - react-temml/.gitignore | 4 - react-temml/README.md | 15 - react-temml/index.html | 12 - react-temml/package.json | 29 - react-temml/src/App.tsx | 5 - react-temml/src/app.css | 12 - .../editor/examples/temml/editor.tsx | 37 - .../editor/examples/temml/extension.ts | 17 - .../components/editor/examples/temml/index.ts | 1 - .../editor/sample/sample-doc-tex.ts | 60 -- .../src/components/editor/sample/temml.ts | 17 - react-temml/src/main.tsx | 10 - react-temml/tsconfig.app.json | 28 - react-temml/tsconfig.json | 7 - react-temml/tsconfig.node.json | 26 - react-temml/vite.config.ts | 8 - react-text-align/.gitignore | 4 - react-text-align/README.md | 15 - react-text-align/index.html | 12 - react-text-align/package.json | 28 - react-text-align/src/App.tsx | 5 - react-text-align/src/app.css | 12 - .../editor/examples/text-align/editor.tsx | 39 - .../editor/examples/text-align/extension.ts | 12 - .../editor/examples/text-align/index.ts | 1 - .../editor/examples/text-align/toolbar.tsx | 80 -- .../editor/sample/sample-doc-text-align.ts | 56 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - react-text-align/src/main.tsx | 10 - react-text-align/tsconfig.app.json | 28 - react-text-align/tsconfig.json | 7 - react-text-align/tsconfig.node.json | 26 - react-text-align/vite.config.ts | 8 - react-text-color/.gitignore | 4 - react-text-color/README.md | 15 - react-text-color/index.html | 12 - react-text-color/package.json | 28 - react-text-color/src/App.tsx | 5 - react-text-color/src/app.css | 12 - .../editor/examples/text-color/editor.tsx | 39 - .../editor/examples/text-color/extension.ts | 14 - .../editor/examples/text-color/index.ts | 1 - .../examples/text-color/inline-menu.tsx | 147 ---- .../editor/sample/sample-doc-text-color.ts | 120 --- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - react-text-color/src/main.tsx | 10 - react-text-color/tsconfig.app.json | 28 - react-text-color/tsconfig.json | 7 - react-text-color/tsconfig.node.json | 26 - react-text-color/vite.config.ts | 8 - react-toolbar/.gitignore | 4 - react-toolbar/README.md | 15 - react-toolbar/index.html | 12 - react-toolbar/package.json | 28 - react-toolbar/src/App.tsx | 5 - react-toolbar/src/app.css | 12 - .../editor/examples/toolbar/editor.tsx | 34 - .../editor/examples/toolbar/extension.ts | 8 - .../editor/examples/toolbar/index.ts | 1 - .../editor/sample/sample-uploader.ts | 54 -- .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-toolbar/src/main.tsx | 10 - react-toolbar/tsconfig.app.json | 28 - react-toolbar/tsconfig.json | 7 - react-toolbar/tsconfig.node.json | 26 - react-toolbar/vite.config.ts | 8 - react-tweet/.gitignore | 4 - react-tweet/README.md | 15 - react-tweet/index.html | 12 - react-tweet/package.json | 30 - react-tweet/src/App.tsx | 5 - react-tweet/src/app.css | 12 - .../editor/examples/tweet/editor.tsx | 53 -- .../editor/examples/tweet/extension.ts | 43 -- .../components/editor/examples/tweet/index.ts | 1 - .../editor/examples/tweet/method-select.tsx | 42 -- .../editor/examples/tweet/tweet-view.tsx | 27 - .../editor/sample/sample-doc-tweet.ts | 22 - react-tweet/src/main.tsx | 10 - react-tweet/tsconfig.app.json | 28 - react-tweet/tsconfig.json | 7 - react-tweet/tsconfig.node.json | 26 - react-tweet/vite.config.ts | 8 - react-typography/.gitignore | 4 - react-typography/README.md | 15 - react-typography/index.html | 12 - react-typography/package.json | 29 - react-typography/src/App.tsx | 5 - react-typography/src/app.css | 12 - .../editor/examples/typography/editor.tsx | 41 -- .../editor/examples/typography/extension.ts | 17 - .../editor/examples/typography/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-typography.ts | 693 ------------------ .../editor/ui/block-handle/block-handle.tsx | 33 - .../editor/ui/block-handle/index.ts | 1 - .../ui/drop-indicator/drop-indicator.tsx | 7 - .../editor/ui/drop-indicator/index.ts | 1 - react-typography/src/main.tsx | 10 - react-typography/tsconfig.app.json | 28 - react-typography/tsconfig.json | 7 - react-typography/tsconfig.node.json | 26 - react-typography/vite.config.ts | 8 - react-underline/.gitignore | 4 - react-underline/README.md | 15 - react-underline/index.html | 12 - react-underline/package.json | 28 - react-underline/src/App.tsx | 5 - react-underline/src/app.css | 12 - .../editor/examples/underline/editor.tsx | 39 - .../editor/examples/underline/extension.ts | 17 - .../editor/examples/underline/index.ts | 1 - .../editor/sample/sample-doc-underline.ts | 30 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-underline/src/main.tsx | 10 - react-underline/tsconfig.app.json | 28 - react-underline/tsconfig.json | 7 - react-underline/tsconfig.node.json | 26 - react-underline/vite.config.ts | 8 - react-unmount/.gitignore | 4 - react-unmount/README.md | 15 - react-unmount/index.html | 12 - react-unmount/package.json | 28 - react-unmount/src/App.tsx | 5 - react-unmount/src/app.css | 12 - .../examples/unmount/editor-component.tsx | 34 - .../editor/examples/unmount/editor.tsx | 46 -- .../examples/unmount/extension-component.tsx | 16 - .../editor/examples/unmount/index.ts | 1 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 221 ------ react-unmount/src/main.tsx | 10 - react-unmount/tsconfig.app.json | 28 - react-unmount/tsconfig.json | 7 - react-unmount/tsconfig.node.json | 26 - react-unmount/vite.config.ts | 8 - react-user-menu-dynamic/.gitignore | 4 - react-user-menu-dynamic/README.md | 15 - react-user-menu-dynamic/index.html | 12 - react-user-menu-dynamic/package.json | 28 - react-user-menu-dynamic/src/App.tsx | 5 - react-user-menu-dynamic/src/app.css | 12 - .../examples/user-menu-dynamic/editor.tsx | 32 - .../examples/user-menu-dynamic/extension.ts | 16 - .../examples/user-menu-dynamic/index.ts | 1 - .../user-menu-dynamic/use-user-query.ts | 40 - .../user-menu-dynamic/user-menu-dynamic.tsx | 23 - .../editor/sample/sample-query-users.ts | 40 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 64 -- react-user-menu-dynamic/src/main.tsx | 10 - react-user-menu-dynamic/tsconfig.app.json | 28 - react-user-menu-dynamic/tsconfig.json | 7 - react-user-menu-dynamic/tsconfig.node.json | 26 - react-user-menu-dynamic/vite.config.ts | 8 - react-user-menu/.gitignore | 4 - react-user-menu/README.md | 15 - react-user-menu/index.html | 12 - react-user-menu/package.json | 28 - react-user-menu/src/App.tsx | 5 - react-user-menu/src/app.css | 12 - .../editor/examples/user-menu/editor.tsx | 37 - .../editor/examples/user-menu/extension.ts | 16 - .../editor/examples/user-menu/index.ts | 1 - .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.tsx | 54 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 64 -- react-user-menu/src/main.tsx | 10 - react-user-menu/tsconfig.app.json | 28 - react-user-menu/tsconfig.json | 7 - react-user-menu/tsconfig.node.json | 26 - react-user-menu/vite.config.ts | 8 - react-word-counter/.gitignore | 4 - react-word-counter/README.md | 15 - react-word-counter/index.html | 12 - react-word-counter/package.json | 28 - react-word-counter/src/App.tsx | 5 - react-word-counter/src/app.css | 12 - .../editor/examples/word-counter/editor.tsx | 42 -- .../editor/examples/word-counter/extension.ts | 8 - .../editor/examples/word-counter/index.ts | 1 - .../editor/sample/sample-doc-word-counter.ts | 16 - .../editor/ui/word-counter/index.ts | 1 - .../editor/ui/word-counter/word-counter.tsx | 24 - react-word-counter/src/main.tsx | 10 - react-word-counter/tsconfig.app.json | 28 - react-word-counter/tsconfig.json | 7 - react-word-counter/tsconfig.node.json | 26 - react-word-counter/vite.config.ts | 8 - react-yjs/.gitignore | 4 - react-yjs/README.md | 15 - react-yjs/index.html | 12 - react-yjs/package.json | 32 - react-yjs/src/App.tsx | 5 - react-yjs/src/app.css | 12 - .../editor/examples/yjs/editor-component.tsx | 43 -- .../components/editor/examples/yjs/editor.tsx | 18 - .../editor/examples/yjs/extension.ts | 48 -- .../components/editor/examples/yjs/index.ts | 1 - .../components/editor/ui/button/button.tsx | 46 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 145 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 365 --------- react-yjs/src/main.tsx | 10 - react-yjs/tsconfig.app.json | 28 - react-yjs/tsconfig.json | 7 - react-yjs/tsconfig.node.json | 26 - react-yjs/vite.config.ts | 8 - solid-block-handle/.gitignore | 4 - solid-block-handle/README.md | 15 - solid-block-handle/index.html | 12 - solid-block-handle/package.json | 25 - solid-block-handle/src/App.tsx | 5 - solid-block-handle/src/app.css | 12 - .../editor/examples/block-handle/editor.tsx | 37 - .../editor/examples/block-handle/extension.ts | 10 - .../editor/examples/block-handle/index.ts | 1 - .../editor/sample/sample-doc-block-handle.ts | 323 -------- .../editor/ui/block-handle/block-handle.tsx | 32 - .../editor/ui/block-handle/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 36 - .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.tsx | 6 - .../editor/ui/drop-indicator/index.ts | 1 - solid-block-handle/src/index.tsx | 8 - solid-block-handle/tsconfig.app.json | 29 - solid-block-handle/tsconfig.json | 7 - solid-block-handle/tsconfig.node.json | 26 - solid-block-handle/vite.config.ts | 7 - solid-blockquote/.gitignore | 4 - solid-blockquote/README.md | 15 - solid-blockquote/index.html | 12 - solid-blockquote/package.json | 25 - solid-blockquote/src/App.tsx | 5 - solid-blockquote/src/app.css | 12 - .../editor/examples/blockquote/editor.tsx | 29 - .../editor/examples/blockquote/extension.ts | 17 - .../editor/examples/blockquote/index.ts | 1 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-blockquote/src/index.tsx | 8 - solid-blockquote/tsconfig.app.json | 29 - solid-blockquote/tsconfig.json | 7 - solid-blockquote/tsconfig.node.json | 26 - solid-blockquote/vite.config.ts | 7 - solid-bold/.gitignore | 4 - solid-bold/README.md | 15 - solid-bold/index.html | 12 - solid-bold/package.json | 25 - solid-bold/src/App.tsx | 5 - solid-bold/src/app.css | 12 - .../editor/examples/bold/editor.tsx | 35 - .../editor/examples/bold/extension.ts | 17 - .../components/editor/examples/bold/index.ts | 1 - .../editor/sample/sample-doc-bold.ts | 44 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-bold/src/index.tsx | 8 - solid-bold/tsconfig.app.json | 29 - solid-bold/tsconfig.json | 7 - solid-bold/tsconfig.node.json | 26 - solid-bold/vite.config.ts | 7 - solid-change-tracking/.gitignore | 4 - solid-change-tracking/README.md | 15 - solid-change-tracking/index.html | 12 - solid-change-tracking/package.json | 25 - solid-change-tracking/src/App.tsx | 5 - solid-change-tracking/src/app.css | 12 - .../examples/change-tracking/editor-diff.tsx | 28 - .../examples/change-tracking/editor-main.tsx | 38 - .../examples/change-tracking/editor.tsx | 82 --- .../editor/examples/change-tracking/index.ts | 1 - solid-change-tracking/src/index.tsx | 8 - solid-change-tracking/tsconfig.app.json | 29 - solid-change-tracking/tsconfig.json | 7 - solid-change-tracking/tsconfig.node.json | 26 - solid-change-tracking/vite.config.ts | 7 - solid-code-block-themes/.gitignore | 4 - solid-code-block-themes/README.md | 15 - solid-code-block-themes/index.html | 12 - solid-code-block-themes/package.json | 25 - solid-code-block-themes/src/App.tsx | 5 - solid-code-block-themes/src/app.css | 12 - .../examples/code-block-themes/editor.tsx | 35 - .../examples/code-block-themes/extension.ts | 10 - .../examples/code-block-themes/index.ts | 1 - .../code-block-themes/theme-selector.tsx | 31 - .../examples/code-block-themes/toolbar.tsx | 11 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../ui/code-block-view/code-block-view.tsx | 36 - .../editor/ui/code-block-view/index.ts | 15 - solid-code-block-themes/src/index.tsx | 8 - solid-code-block-themes/tsconfig.app.json | 29 - solid-code-block-themes/tsconfig.json | 7 - solid-code-block-themes/tsconfig.node.json | 26 - solid-code-block-themes/vite.config.ts | 7 - solid-code-block/.gitignore | 4 - solid-code-block/README.md | 15 - solid-code-block/index.html | 12 - solid-code-block/package.json | 25 - solid-code-block/src/App.tsx | 5 - solid-code-block/src/app.css | 12 - .../editor/examples/code-block/editor.tsx | 35 - .../editor/examples/code-block/extension.ts | 24 - .../editor/examples/code-block/index.ts | 1 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 36 - .../editor/ui/code-block-view/index.ts | 15 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-code-block/src/index.tsx | 8 - solid-code-block/tsconfig.app.json | 29 - solid-code-block/tsconfig.json | 7 - solid-code-block/tsconfig.node.json | 26 - solid-code-block/vite.config.ts | 7 - solid-code/.gitignore | 4 - solid-code/README.md | 15 - solid-code/index.html | 12 - solid-code/package.json | 25 - solid-code/src/App.tsx | 5 - solid-code/src/app.css | 12 - .../editor/examples/code/editor.tsx | 35 - .../editor/examples/code/extension.ts | 17 - .../components/editor/examples/code/index.ts | 1 - .../editor/sample/sample-doc-code.ts | 30 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-code/src/index.tsx | 8 - solid-code/tsconfig.app.json | 29 - solid-code/tsconfig.json | 7 - solid-code/tsconfig.node.json | 26 - solid-code/vite.config.ts | 7 - solid-drop-cursor/.gitignore | 4 - solid-drop-cursor/README.md | 15 - solid-drop-cursor/index.html | 12 - solid-drop-cursor/package.json | 25 - solid-drop-cursor/src/App.tsx | 5 - solid-drop-cursor/src/app.css | 12 - .../editor/examples/drop-cursor/editor.tsx | 33 - .../editor/examples/drop-cursor/extension.ts | 23 - .../editor/examples/drop-cursor/index.ts | 1 - .../editor/sample/sample-doc-drop-cursor.ts | 40 - solid-drop-cursor/src/index.tsx | 8 - solid-drop-cursor/tsconfig.app.json | 29 - solid-drop-cursor/tsconfig.json | 7 - solid-drop-cursor/tsconfig.node.json | 26 - solid-drop-cursor/vite.config.ts | 7 - solid-emoji-rules/.gitignore | 4 - solid-emoji-rules/README.md | 15 - solid-emoji-rules/index.html | 12 - solid-emoji-rules/package.json | 25 - solid-emoji-rules/src/App.tsx | 5 - solid-emoji-rules/src/app.css | 12 - .../editor/examples/emoji-rules/editor.tsx | 26 - .../editor/examples/emoji-rules/emoji.ts | 15 - .../editor/examples/emoji-rules/extension.ts | 15 - .../editor/examples/emoji-rules/index.ts | 1 - solid-emoji-rules/src/index.tsx | 8 - solid-emoji-rules/tsconfig.app.json | 29 - solid-emoji-rules/tsconfig.json | 7 - solid-emoji-rules/tsconfig.node.json | 26 - solid-emoji-rules/vite.config.ts | 7 - solid-full/.gitignore | 4 - solid-full/README.md | 15 - solid-full/index.html | 12 - solid-full/package.json | 26 - solid-full/src/App.tsx | 5 - solid-full/src/app.css | 12 - .../editor/examples/full/editor.tsx | 52 -- .../editor/examples/full/extension.ts | 34 - .../components/editor/examples/full/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-full.ts | 442 ----------- .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/sample/sample-user-data.ts | 54 -- .../editor/ui/block-handle/block-handle.tsx | 32 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.tsx | 36 - .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.tsx | 6 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../editor/ui/image-view/image-view.tsx | 90 --- .../components/editor/ui/image-view/index.ts | 14 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 233 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 10 - .../editor/ui/slash-menu/slash-menu-item.tsx | 22 - .../editor/ui/slash-menu/slash-menu.tsx | 101 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 187 ----- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.tsx | 54 -- .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 64 -- solid-full/src/index.tsx | 8 - solid-full/tsconfig.app.json | 29 - solid-full/tsconfig.json | 7 - solid-full/tsconfig.node.json | 26 - solid-full/vite.config.ts | 7 - solid-gap-cursor/.gitignore | 4 - solid-gap-cursor/README.md | 15 - solid-gap-cursor/index.html | 12 - solid-gap-cursor/package.json | 25 - solid-gap-cursor/src/App.tsx | 5 - solid-gap-cursor/src/app.css | 12 - .../editor/examples/gap-cursor/editor.tsx | 33 - .../editor/examples/gap-cursor/extension.ts | 19 - .../editor/examples/gap-cursor/index.ts | 1 - .../editor/sample/sample-doc-gap-cursor.ts | 28 - solid-gap-cursor/src/index.tsx | 8 - solid-gap-cursor/tsconfig.app.json | 29 - solid-gap-cursor/tsconfig.json | 7 - solid-gap-cursor/tsconfig.node.json | 26 - solid-gap-cursor/vite.config.ts | 7 - solid-hard-break/.gitignore | 4 - solid-hard-break/README.md | 15 - solid-hard-break/index.html | 12 - solid-hard-break/package.json | 25 - solid-hard-break/src/App.tsx | 5 - solid-hard-break/src/app.css | 12 - .../editor/examples/hard-break/editor.tsx | 35 - .../editor/examples/hard-break/extension.ts | 17 - .../editor/examples/hard-break/index.ts | 1 - .../editor/examples/hard-break/toolbar.tsx | 32 - .../editor/sample/sample-doc-hard-break.ts | 68 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - solid-hard-break/src/index.tsx | 8 - solid-hard-break/tsconfig.app.json | 29 - solid-hard-break/tsconfig.json | 7 - solid-hard-break/tsconfig.node.json | 26 - solid-hard-break/vite.config.ts | 7 - solid-heading/.gitignore | 4 - solid-heading/README.md | 15 - solid-heading/index.html | 12 - solid-heading/package.json | 25 - solid-heading/src/App.tsx | 5 - solid-heading/src/app.css | 12 - .../editor/examples/heading/editor.tsx | 35 - .../editor/examples/heading/extension.ts | 17 - .../editor/examples/heading/index.ts | 1 - .../editor/sample/sample-doc-heading.ts | 23 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-heading/src/index.tsx | 8 - solid-heading/tsconfig.app.json | 29 - solid-heading/tsconfig.json | 7 - solid-heading/tsconfig.node.json | 26 - solid-heading/vite.config.ts | 7 - solid-highlight/.gitignore | 4 - solid-highlight/README.md | 15 - solid-highlight/index.html | 12 - solid-highlight/package.json | 25 - solid-highlight/src/App.tsx | 5 - solid-highlight/src/app.css | 12 - .../editor/examples/highlight/editor.tsx | 35 - .../editor/examples/highlight/extension.ts | 17 - .../editor/examples/highlight/index.ts | 1 - .../editor/examples/highlight/toolbar.tsx | 33 - .../editor/sample/sample-doc-highlight.ts | 30 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - solid-highlight/src/index.tsx | 8 - solid-highlight/tsconfig.app.json | 29 - solid-highlight/tsconfig.json | 7 - solid-highlight/tsconfig.node.json | 26 - solid-highlight/vite.config.ts | 7 - solid-horizontal-rule/.gitignore | 4 - solid-horizontal-rule/README.md | 15 - solid-horizontal-rule/index.html | 12 - solid-horizontal-rule/package.json | 25 - solid-horizontal-rule/src/App.tsx | 5 - solid-horizontal-rule/src/app.css | 12 - .../examples/horizontal-rule/editor.tsx | 29 - .../examples/horizontal-rule/extension.ts | 17 - .../editor/examples/horizontal-rule/index.ts | 1 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-horizontal-rule/src/index.tsx | 8 - solid-horizontal-rule/tsconfig.app.json | 29 - solid-horizontal-rule/tsconfig.json | 7 - solid-horizontal-rule/tsconfig.node.json | 26 - solid-horizontal-rule/vite.config.ts | 7 - solid-image-view/.gitignore | 4 - solid-image-view/README.md | 15 - solid-image-view/index.html | 12 - solid-image-view/package.json | 25 - solid-image-view/src/App.tsx | 5 - solid-image-view/src/app.css | 12 - .../editor/examples/image-view/editor.tsx | 33 - .../editor/examples/image-view/extension.ts | 18 - .../editor/examples/image-view/index.ts | 1 - .../editor/sample/sample-doc-image.ts | 32 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/image-view/image-view.tsx | 90 --- .../components/editor/ui/image-view/index.ts | 14 - solid-image-view/src/index.tsx | 8 - solid-image-view/tsconfig.app.json | 29 - solid-image-view/tsconfig.json | 7 - solid-image-view/tsconfig.node.json | 26 - solid-image-view/vite.config.ts | 7 - solid-inline-menu/.gitignore | 4 - solid-inline-menu/README.md | 15 - solid-inline-menu/index.html | 12 - solid-inline-menu/package.json | 25 - solid-inline-menu/src/App.tsx | 5 - solid-inline-menu/src/app.css | 12 - .../editor/examples/inline-menu/editor.tsx | 35 - .../editor/examples/inline-menu/extension.ts | 7 - .../editor/examples/inline-menu/index.ts | 1 - .../editor/sample/sample-doc-inline-menu.ts | 33 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 233 ------ solid-inline-menu/src/index.tsx | 8 - solid-inline-menu/tsconfig.app.json | 29 - solid-inline-menu/tsconfig.json | 7 - solid-inline-menu/tsconfig.node.json | 26 - solid-inline-menu/vite.config.ts | 7 - solid-italic/.gitignore | 4 - solid-italic/README.md | 15 - solid-italic/index.html | 12 - solid-italic/package.json | 25 - solid-italic/src/App.tsx | 5 - solid-italic/src/app.css | 12 - .../editor/examples/italic/editor.tsx | 35 - .../editor/examples/italic/extension.ts | 17 - .../editor/examples/italic/index.ts | 1 - .../editor/sample/sample-doc-italic.ts | 44 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-italic/src/index.tsx | 8 - solid-italic/tsconfig.app.json | 29 - solid-italic/tsconfig.json | 7 - solid-italic/tsconfig.node.json | 26 - solid-italic/vite.config.ts | 7 - solid-katex/.gitignore | 4 - solid-katex/README.md | 15 - solid-katex/index.html | 12 - solid-katex/package.json | 26 - solid-katex/src/App.tsx | 5 - solid-katex/src/app.css | 12 - .../editor/examples/katex/editor.tsx | 33 - .../editor/examples/katex/extension.ts | 17 - .../components/editor/examples/katex/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-tex.ts | 60 -- solid-katex/src/index.tsx | 8 - solid-katex/tsconfig.app.json | 29 - solid-katex/tsconfig.json | 7 - solid-katex/tsconfig.node.json | 26 - solid-katex/vite.config.ts | 7 - solid-keymap/.gitignore | 4 - solid-keymap/README.md | 15 - solid-keymap/index.html | 12 - solid-keymap/package.json | 25 - solid-keymap/src/App.tsx | 5 - solid-keymap/src/app.css | 12 - .../editor/examples/keymap/editor.tsx | 51 -- .../editor/examples/keymap/extension.ts | 8 - .../editor/examples/keymap/index.ts | 1 - .../editor/examples/keymap/toolbar.tsx | 31 - .../examples/keymap/use-submit-keymap.ts | 20 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - solid-keymap/src/index.tsx | 8 - solid-keymap/tsconfig.app.json | 29 - solid-keymap/tsconfig.json | 7 - solid-keymap/tsconfig.node.json | 26 - solid-keymap/vite.config.ts | 7 - solid-link-mark-view/.gitignore | 4 - solid-link-mark-view/README.md | 15 - solid-link-mark-view/index.html | 12 - solid-link-mark-view/package.json | 25 - solid-link-mark-view/src/App.tsx | 5 - solid-link-mark-view/src/app.css | 12 - .../editor/examples/link-mark-view/editor.tsx | 33 - .../examples/link-mark-view/extension.ts | 17 - .../editor/examples/link-mark-view/index.ts | 1 - .../examples/link-mark-view/link-view.tsx | 46 -- .../sample/sample-doc-link-mark-view.ts | 30 - solid-link-mark-view/src/index.tsx | 8 - solid-link-mark-view/tsconfig.app.json | 29 - solid-link-mark-view/tsconfig.json | 7 - solid-link-mark-view/tsconfig.node.json | 26 - solid-link-mark-view/vite.config.ts | 7 - solid-link/.gitignore | 4 - solid-link/README.md | 15 - solid-link/index.html | 12 - solid-link/package.json | 25 - solid-link/src/App.tsx | 5 - solid-link/src/app.css | 12 - .../editor/examples/link/editor.tsx | 35 - .../editor/examples/link/extension.ts | 17 - .../components/editor/examples/link/index.ts | 1 - .../editor/sample/sample-doc-link.ts | 30 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 233 ------ solid-link/src/index.tsx | 8 - solid-link/tsconfig.app.json | 29 - solid-link/tsconfig.json | 7 - solid-link/tsconfig.node.json | 26 - solid-link/vite.config.ts | 7 - solid-list-custom-checkbox/.gitignore | 4 - solid-list-custom-checkbox/README.md | 15 - solid-list-custom-checkbox/index.html | 12 - solid-list-custom-checkbox/package.json | 25 - solid-list-custom-checkbox/src/App.tsx | 5 - solid-list-custom-checkbox/src/app.css | 12 - .../list-custom-checkbox/custom-list.css | 75 -- .../examples/list-custom-checkbox/editor.tsx | 42 -- .../list-custom-checkbox/extension.ts | 8 - .../examples/list-custom-checkbox/index.ts | 1 - .../sample/sample-doc-list-custom-checkbox.ts | 38 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-list-custom-checkbox/src/index.tsx | 8 - solid-list-custom-checkbox/tsconfig.app.json | 29 - solid-list-custom-checkbox/tsconfig.json | 7 - solid-list-custom-checkbox/tsconfig.node.json | 26 - solid-list-custom-checkbox/vite.config.ts | 7 - solid-list/.gitignore | 4 - solid-list/README.md | 15 - solid-list/index.html | 12 - solid-list/package.json | 25 - solid-list/src/App.tsx | 5 - solid-list/src/app.css | 12 - .../editor/examples/list/editor.tsx | 35 - .../editor/examples/list/extension.ts | 17 - .../components/editor/examples/list/index.ts | 1 - .../editor/sample/sample-doc-list.ts | 47 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-list/src/index.tsx | 8 - solid-list/tsconfig.app.json | 29 - solid-list/tsconfig.json | 7 - solid-list/tsconfig.node.json | 26 - solid-list/vite.config.ts | 7 - solid-loro/.gitignore | 4 - solid-loro/README.md | 15 - solid-loro/index.html | 12 - solid-loro/package.json | 28 - solid-loro/src/App.tsx | 5 - solid-loro/src/app.css | 12 - .../editor/examples/loro/editor-component.tsx | 34 - .../editor/examples/loro/editor.tsx | 56 -- .../editor/examples/loro/extension.ts | 47 -- .../components/editor/examples/loro/index.ts | 1 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-loro/src/index.tsx | 8 - solid-loro/tsconfig.app.json | 29 - solid-loro/tsconfig.json | 7 - solid-loro/tsconfig.node.json | 26 - solid-loro/vite.config.ts | 8 - solid-mark-rule/.gitignore | 4 - solid-mark-rule/README.md | 15 - solid-mark-rule/index.html | 12 - solid-mark-rule/package.json | 25 - solid-mark-rule/src/App.tsx | 5 - solid-mark-rule/src/app.css | 12 - .../editor/examples/mark-rule/editor.tsx | 26 - .../editor/examples/mark-rule/extension.ts | 32 - .../editor/examples/mark-rule/index.ts | 1 - .../editor/examples/mark-rule/issue-link.ts | 32 - solid-mark-rule/src/index.tsx | 8 - solid-mark-rule/tsconfig.app.json | 29 - solid-mark-rule/tsconfig.json | 7 - solid-mark-rule/tsconfig.node.json | 26 - solid-mark-rule/vite.config.ts | 7 - solid-minimal/.gitignore | 4 - solid-minimal/README.md | 15 - solid-minimal/index.html | 12 - solid-minimal/package.json | 25 - solid-minimal/src/App.tsx | 5 - solid-minimal/src/app.css | 12 - .../editor/examples/minimal/editor.tsx | 18 - .../editor/examples/minimal/index.ts | 1 - solid-minimal/src/index.tsx | 8 - solid-minimal/tsconfig.app.json | 29 - solid-minimal/tsconfig.json | 7 - solid-minimal/tsconfig.node.json | 26 - solid-minimal/vite.config.ts | 7 - solid-placeholder/.gitignore | 4 - solid-placeholder/README.md | 15 - solid-placeholder/index.html | 12 - solid-placeholder/package.json | 25 - solid-placeholder/src/App.tsx | 5 - solid-placeholder/src/app.css | 12 - .../editor/examples/placeholder/editor.tsx | 37 - .../editor/examples/placeholder/extension.ts | 12 - .../editor/examples/placeholder/index.ts | 1 - solid-placeholder/src/index.tsx | 8 - solid-placeholder/tsconfig.app.json | 29 - solid-placeholder/tsconfig.json | 7 - solid-placeholder/tsconfig.node.json | 26 - solid-placeholder/vite.config.ts | 7 - solid-readonly/.gitignore | 4 - solid-readonly/README.md | 15 - solid-readonly/index.html | 12 - solid-readonly/package.json | 25 - solid-readonly/src/App.tsx | 5 - solid-readonly/src/app.css | 12 - .../editor/examples/readonly/editor.tsx | 35 - .../editor/examples/readonly/extension.ts | 7 - .../editor/examples/readonly/index.ts | 1 - .../editor/examples/readonly/toolbar.tsx | 21 - .../editor/examples/readonly/use-readonly.ts | 14 - .../editor/sample/sample-doc-readonly.ts | 16 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - solid-readonly/src/index.tsx | 8 - solid-readonly/tsconfig.app.json | 29 - solid-readonly/tsconfig.json | 7 - solid-readonly/tsconfig.node.json | 26 - solid-readonly/vite.config.ts | 7 - solid-rtl/.gitignore | 4 - solid-rtl/README.md | 15 - solid-rtl/index.html | 12 - solid-rtl/package.json | 25 - solid-rtl/src/App.tsx | 5 - solid-rtl/src/app.css | 12 - .../components/editor/examples/rtl/editor.tsx | 48 -- .../components/editor/examples/rtl/index.ts | 1 - .../editor/sample/sample-doc-rtl.ts | 187 ----- .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/block-handle/block-handle.tsx | 32 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/drop-indicator/drop-indicator.tsx | 6 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 233 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 10 - .../editor/ui/slash-menu/slash-menu-item.tsx | 22 - .../editor/ui/slash-menu/slash-menu.tsx | 101 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 187 ----- .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-rtl/src/index.tsx | 8 - solid-rtl/tsconfig.app.json | 29 - solid-rtl/tsconfig.json | 7 - solid-rtl/tsconfig.node.json | 26 - solid-rtl/vite.config.ts | 7 - solid-save-html/.gitignore | 4 - solid-save-html/README.md | 15 - solid-save-html/index.html | 12 - solid-save-html/package.json | 25 - solid-save-html/src/App.tsx | 5 - solid-save-html/src/app.css | 12 - .../editor/examples/save-html/editor.tsx | 66 -- .../editor/examples/save-html/index.ts | 1 - solid-save-html/src/index.tsx | 8 - solid-save-html/tsconfig.app.json | 29 - solid-save-html/tsconfig.json | 7 - solid-save-html/tsconfig.node.json | 26 - solid-save-html/vite.config.ts | 7 - solid-save-json/.gitignore | 4 - solid-save-json/README.md | 15 - solid-save-json/index.html | 12 - solid-save-json/package.json | 25 - solid-save-json/src/App.tsx | 5 - solid-save-json/src/app.css | 12 - .../editor/examples/save-json/editor.tsx | 66 -- .../editor/examples/save-json/index.ts | 1 - solid-save-json/src/index.tsx | 8 - solid-save-json/tsconfig.app.json | 29 - solid-save-json/tsconfig.json | 7 - solid-save-json/tsconfig.node.json | 26 - solid-save-json/vite.config.ts | 7 - solid-save-markdown/.gitignore | 4 - solid-save-markdown/README.md | 15 - solid-save-markdown/index.html | 12 - solid-save-markdown/package.json | 32 - solid-save-markdown/src/App.tsx | 5 - solid-save-markdown/src/app.css | 12 - .../editor/examples/save-markdown/editor.tsx | 70 -- .../editor/examples/save-markdown/index.ts | 1 - .../editor/examples/save-markdown/markdown.ts | 26 - solid-save-markdown/src/index.tsx | 8 - solid-save-markdown/tsconfig.app.json | 29 - solid-save-markdown/tsconfig.json | 7 - solid-save-markdown/tsconfig.node.json | 26 - solid-save-markdown/vite.config.ts | 7 - solid-search/.gitignore | 4 - solid-search/README.md | 15 - solid-search/index.html | 12 - solid-search/package.json | 25 - solid-search/src/App.tsx | 5 - solid-search/src/app.css | 12 - .../editor/examples/search/editor.tsx | 39 - .../editor/examples/search/extension.ts | 9 - .../editor/examples/search/index.ts | 1 - .../editor/sample/sample-doc-search.ts | 79 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../src/components/editor/ui/search/index.ts | 1 - .../components/editor/ui/search/search.tsx | 170 ----- solid-search/src/index.tsx | 8 - solid-search/tsconfig.app.json | 29 - solid-search/tsconfig.json | 7 - solid-search/tsconfig.node.json | 26 - solid-search/vite.config.ts | 7 - solid-slash-menu/.gitignore | 4 - solid-slash-menu/README.md | 15 - solid-slash-menu/index.html | 12 - solid-slash-menu/package.json | 25 - solid-slash-menu/src/App.tsx | 5 - solid-slash-menu/src/app.css | 12 - .../editor/examples/slash-menu/editor.tsx | 29 - .../editor/examples/slash-menu/extension.ts | 12 - .../editor/examples/slash-menu/index.ts | 1 - .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.tsx | 10 - .../editor/ui/slash-menu/slash-menu-item.tsx | 22 - .../editor/ui/slash-menu/slash-menu.tsx | 101 --- solid-slash-menu/src/index.tsx | 8 - solid-slash-menu/tsconfig.app.json | 29 - solid-slash-menu/tsconfig.json | 7 - solid-slash-menu/tsconfig.node.json | 26 - solid-slash-menu/vite.config.ts | 7 - solid-strike/.gitignore | 4 - solid-strike/README.md | 15 - solid-strike/index.html | 12 - solid-strike/package.json | 25 - solid-strike/src/App.tsx | 5 - solid-strike/src/app.css | 12 - .../editor/examples/strike/editor.tsx | 35 - .../editor/examples/strike/extension.ts | 17 - .../editor/examples/strike/index.ts | 1 - .../editor/examples/strike/toolbar.tsx | 33 - .../editor/sample/sample-doc-strike.ts | 30 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - solid-strike/src/index.tsx | 8 - solid-strike/tsconfig.app.json | 29 - solid-strike/tsconfig.json | 7 - solid-strike/tsconfig.node.json | 26 - solid-strike/vite.config.ts | 7 - solid-sub-sup/.gitignore | 4 - solid-sub-sup/README.md | 15 - solid-sub-sup/index.html | 12 - solid-sub-sup/package.json | 25 - solid-sub-sup/src/App.tsx | 5 - solid-sub-sup/src/app.css | 12 - .../editor/examples/sub-sup/editor.tsx | 35 - .../editor/examples/sub-sup/extension.ts | 32 - .../editor/examples/sub-sup/index.ts | 1 - .../editor/examples/sub-sup/toolbar.tsx | 45 -- .../editor/sample/sample-doc-sub-sup.ts | 42 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - solid-sub-sup/src/index.tsx | 8 - solid-sub-sup/tsconfig.app.json | 29 - solid-sub-sup/tsconfig.json | 7 - solid-sub-sup/tsconfig.node.json | 26 - solid-sub-sup/vite.config.ts | 7 - solid-table/.gitignore | 4 - solid-table/README.md | 15 - solid-table/index.html | 12 - solid-table/package.json | 25 - solid-table/src/App.tsx | 5 - solid-table/src/app.css | 12 - .../editor/examples/table/editor.tsx | 35 - .../editor/examples/table/extension.ts | 20 - .../components/editor/examples/table/index.ts | 1 - .../editor/sample/sample-doc-table.ts | 174 ----- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.tsx | 187 ----- solid-table/src/index.tsx | 8 - solid-table/tsconfig.app.json | 29 - solid-table/tsconfig.json | 7 - solid-table/tsconfig.node.json | 26 - solid-table/vite.config.ts | 7 - solid-temml/.gitignore | 4 - solid-temml/README.md | 15 - solid-temml/index.html | 12 - solid-temml/package.json | 26 - solid-temml/src/App.tsx | 5 - solid-temml/src/app.css | 12 - .../editor/examples/temml/editor.tsx | 33 - .../editor/examples/temml/extension.ts | 17 - .../components/editor/examples/temml/index.ts | 1 - .../editor/sample/sample-doc-tex.ts | 60 -- .../src/components/editor/sample/temml.ts | 17 - solid-temml/src/index.tsx | 8 - solid-temml/tsconfig.app.json | 29 - solid-temml/tsconfig.json | 7 - solid-temml/tsconfig.node.json | 26 - solid-temml/vite.config.ts | 7 - solid-text-align/.gitignore | 4 - solid-text-align/README.md | 15 - solid-text-align/index.html | 12 - solid-text-align/package.json | 25 - solid-text-align/src/App.tsx | 5 - solid-text-align/src/app.css | 12 - .../editor/examples/text-align/editor.tsx | 35 - .../editor/examples/text-align/extension.ts | 12 - .../editor/examples/text-align/index.ts | 1 - .../editor/examples/text-align/toolbar.tsx | 79 -- .../editor/sample/sample-doc-text-align.ts | 56 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - solid-text-align/src/index.tsx | 8 - solid-text-align/tsconfig.app.json | 29 - solid-text-align/tsconfig.json | 7 - solid-text-align/tsconfig.node.json | 26 - solid-text-align/vite.config.ts | 7 - solid-text-color/.gitignore | 4 - solid-text-color/README.md | 15 - solid-text-color/index.html | 12 - solid-text-color/package.json | 25 - solid-text-color/src/App.tsx | 5 - solid-text-color/src/app.css | 12 - .../editor/examples/text-color/editor.tsx | 35 - .../editor/examples/text-color/extension.ts | 14 - .../editor/examples/text-color/index.ts | 1 - .../examples/text-color/inline-menu.tsx | 144 ---- .../editor/sample/sample-doc-text-color.ts | 120 --- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - solid-text-color/src/index.tsx | 8 - solid-text-color/tsconfig.app.json | 29 - solid-text-color/tsconfig.json | 7 - solid-text-color/tsconfig.node.json | 26 - solid-text-color/vite.config.ts | 7 - solid-toolbar/.gitignore | 4 - solid-toolbar/README.md | 15 - solid-toolbar/index.html | 12 - solid-toolbar/package.json | 25 - solid-toolbar/src/App.tsx | 5 - solid-toolbar/src/app.css | 12 - .../editor/examples/toolbar/editor.tsx | 30 - .../editor/examples/toolbar/extension.ts | 8 - .../editor/examples/toolbar/index.ts | 1 - .../editor/sample/sample-uploader.ts | 54 -- .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-toolbar/src/index.tsx | 8 - solid-toolbar/tsconfig.app.json | 29 - solid-toolbar/tsconfig.json | 7 - solid-toolbar/tsconfig.node.json | 26 - solid-toolbar/vite.config.ts | 7 - solid-typography/.gitignore | 4 - solid-typography/README.md | 15 - solid-typography/index.html | 12 - solid-typography/package.json | 26 - solid-typography/src/App.tsx | 5 - solid-typography/src/app.css | 12 - .../editor/examples/typography/editor.tsx | 37 - .../editor/examples/typography/extension.ts | 17 - .../editor/examples/typography/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-typography.ts | 693 ------------------ .../editor/ui/block-handle/block-handle.tsx | 32 - .../editor/ui/block-handle/index.ts | 1 - .../ui/drop-indicator/drop-indicator.tsx | 6 - .../editor/ui/drop-indicator/index.ts | 1 - solid-typography/src/index.tsx | 8 - solid-typography/tsconfig.app.json | 29 - solid-typography/tsconfig.json | 7 - solid-typography/tsconfig.node.json | 26 - solid-typography/vite.config.ts | 7 - solid-underline/.gitignore | 4 - solid-underline/README.md | 15 - solid-underline/index.html | 12 - solid-underline/package.json | 25 - solid-underline/src/App.tsx | 5 - solid-underline/src/app.css | 12 - .../editor/examples/underline/editor.tsx | 35 - .../editor/examples/underline/extension.ts | 17 - .../editor/examples/underline/index.ts | 1 - .../editor/sample/sample-doc-underline.ts | 30 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-underline/src/index.tsx | 8 - solid-underline/tsconfig.app.json | 29 - solid-underline/tsconfig.json | 7 - solid-underline/tsconfig.node.json | 26 - solid-underline/vite.config.ts | 7 - solid-unmount/.gitignore | 4 - solid-unmount/README.md | 15 - solid-unmount/index.html | 12 - solid-unmount/package.json | 25 - solid-unmount/src/App.tsx | 5 - solid-unmount/src/app.css | 12 - .../examples/unmount/editor-component.tsx | 33 - .../editor/examples/unmount/editor.tsx | 42 -- .../examples/unmount/extension-component.tsx | 15 - .../editor/examples/unmount/index.ts | 1 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.tsx | 233 ------ solid-unmount/src/index.tsx | 8 - solid-unmount/tsconfig.app.json | 29 - solid-unmount/tsconfig.json | 7 - solid-unmount/tsconfig.node.json | 26 - solid-unmount/vite.config.ts | 7 - solid-user-menu-dynamic/.gitignore | 4 - solid-user-menu-dynamic/README.md | 15 - solid-user-menu-dynamic/index.html | 12 - solid-user-menu-dynamic/package.json | 25 - solid-user-menu-dynamic/src/App.tsx | 5 - solid-user-menu-dynamic/src/app.css | 12 - .../examples/user-menu-dynamic/editor.tsx | 28 - .../examples/user-menu-dynamic/extension.ts | 16 - .../examples/user-menu-dynamic/index.ts | 1 - .../user-menu-dynamic/use-user-query.ts | 42 -- .../user-menu-dynamic/user-menu-dynamic.tsx | 21 - .../editor/sample/sample-query-users.ts | 40 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 64 -- solid-user-menu-dynamic/src/index.tsx | 8 - solid-user-menu-dynamic/tsconfig.app.json | 29 - solid-user-menu-dynamic/tsconfig.json | 7 - solid-user-menu-dynamic/tsconfig.node.json | 26 - solid-user-menu-dynamic/vite.config.ts | 7 - solid-user-menu/.gitignore | 4 - solid-user-menu/README.md | 15 - solid-user-menu/index.html | 12 - solid-user-menu/package.json | 25 - solid-user-menu/src/App.tsx | 5 - solid-user-menu/src/app.css | 12 - .../editor/examples/user-menu/editor.tsx | 33 - .../editor/examples/user-menu/extension.ts | 16 - .../editor/examples/user-menu/index.ts | 1 - .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.tsx | 54 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.tsx | 64 -- solid-user-menu/src/index.tsx | 8 - solid-user-menu/tsconfig.app.json | 29 - solid-user-menu/tsconfig.json | 7 - solid-user-menu/tsconfig.node.json | 26 - solid-user-menu/vite.config.ts | 7 - solid-word-counter/.gitignore | 4 - solid-word-counter/README.md | 15 - solid-word-counter/index.html | 12 - solid-word-counter/package.json | 25 - solid-word-counter/src/App.tsx | 5 - solid-word-counter/src/app.css | 12 - .../editor/examples/word-counter/editor.tsx | 35 - .../editor/examples/word-counter/extension.ts | 8 - .../editor/examples/word-counter/index.ts | 1 - .../editor/sample/sample-doc-word-counter.ts | 16 - .../editor/ui/word-counter/index.ts | 1 - .../editor/ui/word-counter/word-counter.tsx | 23 - solid-word-counter/src/index.tsx | 8 - solid-word-counter/tsconfig.app.json | 29 - solid-word-counter/tsconfig.json | 7 - solid-word-counter/tsconfig.node.json | 26 - solid-word-counter/vite.config.ts | 7 - solid-yjs/.gitignore | 4 - solid-yjs/README.md | 15 - solid-yjs/index.html | 12 - solid-yjs/package.json | 29 - solid-yjs/src/App.tsx | 5 - solid-yjs/src/app.css | 12 - .../editor/examples/yjs/editor-component.tsx | 41 -- .../components/editor/examples/yjs/editor.tsx | 14 - .../editor/examples/yjs/extension.ts | 48 -- .../components/editor/examples/yjs/index.ts | 1 - .../components/editor/ui/button/button.tsx | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.tsx | 137 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.tsx | 406 ---------- solid-yjs/src/index.tsx | 8 - solid-yjs/tsconfig.app.json | 29 - solid-yjs/tsconfig.json | 7 - solid-yjs/tsconfig.node.json | 26 - solid-yjs/vite.config.ts | 7 - svelte-block-handle/.gitignore | 4 - svelte-block-handle/README.md | 15 - svelte-block-handle/index.html | 12 - svelte-block-handle/package.json | 28 - svelte-block-handle/src/App.svelte | 5 - svelte-block-handle/src/app.css | 12 - .../examples/block-handle/editor.svelte | 32 - .../editor/examples/block-handle/extension.ts | 10 - .../editor/examples/block-handle/index.ts | 1 - .../editor/sample/sample-doc-block-handle.ts | 323 -------- .../ui/block-handle/block-handle.svelte | 28 - .../editor/ui/block-handle/index.ts | 1 - .../ui/code-block-view/code-block-view.svelte | 40 - .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.svelte | 5 - .../editor/ui/drop-indicator/index.ts | 1 - svelte-block-handle/src/main.ts | 8 - svelte-block-handle/src/vite-env.d.ts | 2 - svelte-block-handle/svelte.config.js | 7 - svelte-block-handle/tsconfig.json | 21 - svelte-block-handle/tsconfig.node.json | 9 - svelte-block-handle/vite.config.ts | 8 - svelte-blockquote/.gitignore | 4 - svelte-blockquote/README.md | 15 - svelte-blockquote/index.html | 12 - svelte-blockquote/package.json | 28 - svelte-blockquote/src/App.svelte | 5 - svelte-blockquote/src/app.css | 12 - .../editor/examples/blockquote/editor.svelte | 23 - .../editor/examples/blockquote/extension.ts | 17 - .../editor/examples/blockquote/index.ts | 1 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-blockquote/src/main.ts | 8 - svelte-blockquote/src/vite-env.d.ts | 2 - svelte-blockquote/svelte.config.js | 7 - svelte-blockquote/tsconfig.json | 21 - svelte-blockquote/tsconfig.node.json | 9 - svelte-blockquote/vite.config.ts | 8 - svelte-bold/.gitignore | 4 - svelte-bold/README.md | 15 - svelte-bold/index.html | 12 - svelte-bold/package.json | 28 - svelte-bold/src/App.svelte | 5 - svelte-bold/src/app.css | 12 - .../editor/examples/bold/editor.svelte | 30 - .../editor/examples/bold/extension.ts | 17 - .../components/editor/examples/bold/index.ts | 1 - .../editor/sample/sample-doc-bold.ts | 44 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-bold/src/main.ts | 8 - svelte-bold/src/vite-env.d.ts | 2 - svelte-bold/svelte.config.js | 7 - svelte-bold/tsconfig.json | 21 - svelte-bold/tsconfig.node.json | 9 - svelte-bold/vite.config.ts | 8 - svelte-change-tracking/.gitignore | 4 - svelte-change-tracking/README.md | 15 - svelte-change-tracking/index.html | 12 - svelte-change-tracking/package.json | 28 - svelte-change-tracking/src/App.svelte | 5 - svelte-change-tracking/src/app.css | 12 - .../change-tracking/editor-diff.svelte | 28 - .../change-tracking/editor-main.svelte | 34 - .../examples/change-tracking/editor.svelte | 63 -- .../editor/examples/change-tracking/index.ts | 1 - svelte-change-tracking/src/main.ts | 8 - svelte-change-tracking/src/vite-env.d.ts | 2 - svelte-change-tracking/svelte.config.js | 7 - svelte-change-tracking/tsconfig.json | 21 - svelte-change-tracking/tsconfig.node.json | 9 - svelte-change-tracking/vite.config.ts | 8 - svelte-code-block-themes/.gitignore | 4 - svelte-code-block-themes/README.md | 15 - svelte-code-block-themes/index.html | 12 - svelte-code-block-themes/package.json | 28 - svelte-code-block-themes/src/App.svelte | 5 - svelte-code-block-themes/src/app.css | 12 - .../examples/code-block-themes/editor.svelte | 30 - .../examples/code-block-themes/extension.ts | 10 - .../examples/code-block-themes/index.ts | 1 - .../code-block-themes/theme-selector.svelte | 29 - .../examples/code-block-themes/toolbar.svelte | 7 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../ui/code-block-view/code-block-view.svelte | 40 - .../editor/ui/code-block-view/index.ts | 15 - svelte-code-block-themes/src/main.ts | 8 - svelte-code-block-themes/src/vite-env.d.ts | 2 - svelte-code-block-themes/svelte.config.js | 7 - svelte-code-block-themes/tsconfig.json | 21 - svelte-code-block-themes/tsconfig.node.json | 9 - svelte-code-block-themes/vite.config.ts | 8 - svelte-code-block/.gitignore | 4 - svelte-code-block/README.md | 15 - svelte-code-block/index.html | 12 - svelte-code-block/package.json | 28 - svelte-code-block/src/App.svelte | 5 - svelte-code-block/src/app.css | 12 - .../editor/examples/code-block/editor.svelte | 30 - .../editor/examples/code-block/extension.ts | 24 - .../editor/examples/code-block/index.ts | 1 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.svelte | 40 - .../editor/ui/code-block-view/index.ts | 15 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-code-block/src/main.ts | 8 - svelte-code-block/src/vite-env.d.ts | 2 - svelte-code-block/svelte.config.js | 7 - svelte-code-block/tsconfig.json | 21 - svelte-code-block/tsconfig.node.json | 9 - svelte-code-block/vite.config.ts | 8 - svelte-code/.gitignore | 4 - svelte-code/README.md | 15 - svelte-code/index.html | 12 - svelte-code/package.json | 28 - svelte-code/src/App.svelte | 5 - svelte-code/src/app.css | 12 - .../editor/examples/code/editor.svelte | 30 - .../editor/examples/code/extension.ts | 17 - .../components/editor/examples/code/index.ts | 1 - .../editor/sample/sample-doc-code.ts | 30 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-code/src/main.ts | 8 - svelte-code/src/vite-env.d.ts | 2 - svelte-code/svelte.config.js | 7 - svelte-code/tsconfig.json | 21 - svelte-code/tsconfig.node.json | 9 - svelte-code/vite.config.ts | 8 - svelte-drop-cursor/.gitignore | 4 - svelte-drop-cursor/README.md | 15 - svelte-drop-cursor/index.html | 12 - svelte-drop-cursor/package.json | 28 - svelte-drop-cursor/src/App.svelte | 5 - svelte-drop-cursor/src/app.css | 12 - .../editor/examples/drop-cursor/editor.svelte | 28 - .../editor/examples/drop-cursor/extension.ts | 23 - .../editor/examples/drop-cursor/index.ts | 1 - .../editor/sample/sample-doc-drop-cursor.ts | 40 - svelte-drop-cursor/src/main.ts | 8 - svelte-drop-cursor/src/vite-env.d.ts | 2 - svelte-drop-cursor/svelte.config.js | 7 - svelte-drop-cursor/tsconfig.json | 21 - svelte-drop-cursor/tsconfig.node.json | 9 - svelte-drop-cursor/vite.config.ts | 8 - svelte-emoji-rules/.gitignore | 4 - svelte-emoji-rules/README.md | 15 - svelte-emoji-rules/index.html | 12 - svelte-emoji-rules/package.json | 28 - svelte-emoji-rules/src/App.svelte | 5 - svelte-emoji-rules/src/app.css | 12 - .../editor/examples/emoji-rules/editor.svelte | 20 - .../editor/examples/emoji-rules/emoji.ts | 15 - .../editor/examples/emoji-rules/extension.ts | 15 - .../editor/examples/emoji-rules/index.ts | 1 - svelte-emoji-rules/src/main.ts | 8 - svelte-emoji-rules/src/vite-env.d.ts | 2 - svelte-emoji-rules/svelte.config.js | 7 - svelte-emoji-rules/tsconfig.json | 21 - svelte-emoji-rules/tsconfig.node.json | 9 - svelte-emoji-rules/vite.config.ts | 8 - svelte-full/.gitignore | 4 - svelte-full/README.md | 15 - svelte-full/index.html | 12 - svelte-full/package.json | 29 - svelte-full/src/App.svelte | 5 - svelte-full/src/app.css | 12 - .../editor/examples/full/editor.svelte | 47 -- .../editor/examples/full/extension.ts | 34 - .../components/editor/examples/full/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-full.ts | 442 ----------- .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/sample/sample-user-data.ts | 54 -- .../ui/block-handle/block-handle.svelte | 28 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.svelte | 40 - .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.svelte | 5 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../editor/ui/image-view/image-view.svelte | 97 --- .../components/editor/ui/image-view/index.ts | 14 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.svelte | 207 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../ui/slash-menu/slash-menu-empty.svelte | 7 - .../ui/slash-menu/slash-menu-item.svelte | 15 - .../editor/ui/slash-menu/slash-menu.svelte | 94 --- .../editor/ui/table-handle/index.ts | 1 - .../ui/table-handle/table-handle.svelte | 182 ----- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.svelte | 53 -- .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.svelte | 70 -- svelte-full/src/main.ts | 8 - svelte-full/src/vite-env.d.ts | 2 - svelte-full/svelte.config.js | 7 - svelte-full/tsconfig.json | 21 - svelte-full/tsconfig.node.json | 9 - svelte-full/vite.config.ts | 8 - svelte-gap-cursor/.gitignore | 4 - svelte-gap-cursor/README.md | 15 - svelte-gap-cursor/index.html | 12 - svelte-gap-cursor/package.json | 28 - svelte-gap-cursor/src/App.svelte | 5 - svelte-gap-cursor/src/app.css | 12 - .../editor/examples/gap-cursor/editor.svelte | 28 - .../editor/examples/gap-cursor/extension.ts | 19 - .../editor/examples/gap-cursor/index.ts | 1 - .../editor/sample/sample-doc-gap-cursor.ts | 28 - svelte-gap-cursor/src/main.ts | 8 - svelte-gap-cursor/src/vite-env.d.ts | 2 - svelte-gap-cursor/svelte.config.js | 7 - svelte-gap-cursor/tsconfig.json | 21 - svelte-gap-cursor/tsconfig.node.json | 9 - svelte-gap-cursor/vite.config.ts | 8 - svelte-hard-break/.gitignore | 4 - svelte-hard-break/README.md | 15 - svelte-hard-break/index.html | 12 - svelte-hard-break/package.json | 28 - svelte-hard-break/src/App.svelte | 5 - svelte-hard-break/src/app.css | 12 - .../editor/examples/hard-break/editor.svelte | 30 - .../editor/examples/hard-break/extension.ts | 17 - .../editor/examples/hard-break/index.ts | 1 - .../editor/examples/hard-break/toolbar.svelte | 29 - .../editor/sample/sample-doc-hard-break.ts | 68 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - svelte-hard-break/src/main.ts | 8 - svelte-hard-break/src/vite-env.d.ts | 2 - svelte-hard-break/svelte.config.js | 7 - svelte-hard-break/tsconfig.json | 21 - svelte-hard-break/tsconfig.node.json | 9 - svelte-hard-break/vite.config.ts | 8 - svelte-heading/.gitignore | 4 - svelte-heading/README.md | 15 - svelte-heading/index.html | 12 - svelte-heading/package.json | 28 - svelte-heading/src/App.svelte | 5 - svelte-heading/src/app.css | 12 - .../editor/examples/heading/editor.svelte | 30 - .../editor/examples/heading/extension.ts | 17 - .../editor/examples/heading/index.ts | 1 - .../editor/sample/sample-doc-heading.ts | 23 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-heading/src/main.ts | 8 - svelte-heading/src/vite-env.d.ts | 2 - svelte-heading/svelte.config.js | 7 - svelte-heading/tsconfig.json | 21 - svelte-heading/tsconfig.node.json | 9 - svelte-heading/vite.config.ts | 8 - svelte-highlight/.gitignore | 4 - svelte-highlight/README.md | 15 - svelte-highlight/index.html | 12 - svelte-highlight/package.json | 28 - svelte-highlight/src/App.svelte | 5 - svelte-highlight/src/app.css | 12 - .../editor/examples/highlight/editor.svelte | 30 - .../editor/examples/highlight/extension.ts | 17 - .../editor/examples/highlight/index.ts | 1 - .../editor/examples/highlight/toolbar.svelte | 30 - .../editor/sample/sample-doc-highlight.ts | 30 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - svelte-highlight/src/main.ts | 8 - svelte-highlight/src/vite-env.d.ts | 2 - svelte-highlight/svelte.config.js | 7 - svelte-highlight/tsconfig.json | 21 - svelte-highlight/tsconfig.node.json | 9 - svelte-highlight/vite.config.ts | 8 - svelte-horizontal-rule/.gitignore | 4 - svelte-horizontal-rule/README.md | 15 - svelte-horizontal-rule/index.html | 12 - svelte-horizontal-rule/package.json | 28 - svelte-horizontal-rule/src/App.svelte | 5 - svelte-horizontal-rule/src/app.css | 12 - .../examples/horizontal-rule/editor.svelte | 23 - .../examples/horizontal-rule/extension.ts | 17 - .../editor/examples/horizontal-rule/index.ts | 1 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-horizontal-rule/src/main.ts | 8 - svelte-horizontal-rule/src/vite-env.d.ts | 2 - svelte-horizontal-rule/svelte.config.js | 7 - svelte-horizontal-rule/tsconfig.json | 21 - svelte-horizontal-rule/tsconfig.node.json | 9 - svelte-horizontal-rule/vite.config.ts | 8 - svelte-image-view/.gitignore | 4 - svelte-image-view/README.md | 15 - svelte-image-view/index.html | 12 - svelte-image-view/package.json | 28 - svelte-image-view/src/App.svelte | 5 - svelte-image-view/src/app.css | 12 - .../editor/examples/image-view/editor.svelte | 28 - .../editor/examples/image-view/extension.ts | 18 - .../editor/examples/image-view/index.ts | 1 - .../editor/sample/sample-doc-image.ts | 32 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/image-view/image-view.svelte | 97 --- .../components/editor/ui/image-view/index.ts | 14 - svelte-image-view/src/main.ts | 8 - svelte-image-view/src/vite-env.d.ts | 2 - svelte-image-view/svelte.config.js | 7 - svelte-image-view/tsconfig.json | 21 - svelte-image-view/tsconfig.node.json | 9 - svelte-image-view/vite.config.ts | 8 - svelte-inline-menu/.gitignore | 4 - svelte-inline-menu/README.md | 15 - svelte-inline-menu/index.html | 12 - svelte-inline-menu/package.json | 28 - svelte-inline-menu/src/App.svelte | 5 - svelte-inline-menu/src/app.css | 12 - .../editor/examples/inline-menu/editor.svelte | 30 - .../editor/examples/inline-menu/extension.ts | 7 - .../editor/examples/inline-menu/index.ts | 1 - .../editor/sample/sample-doc-inline-menu.ts | 33 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.svelte | 207 ------ svelte-inline-menu/src/main.ts | 8 - svelte-inline-menu/src/vite-env.d.ts | 2 - svelte-inline-menu/svelte.config.js | 7 - svelte-inline-menu/tsconfig.json | 21 - svelte-inline-menu/tsconfig.node.json | 9 - svelte-inline-menu/vite.config.ts | 8 - svelte-italic/.gitignore | 4 - svelte-italic/README.md | 15 - svelte-italic/index.html | 12 - svelte-italic/package.json | 28 - svelte-italic/src/App.svelte | 5 - svelte-italic/src/app.css | 12 - .../editor/examples/italic/editor.svelte | 30 - .../editor/examples/italic/extension.ts | 17 - .../editor/examples/italic/index.ts | 1 - .../editor/sample/sample-doc-italic.ts | 44 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-italic/src/main.ts | 8 - svelte-italic/src/vite-env.d.ts | 2 - svelte-italic/svelte.config.js | 7 - svelte-italic/tsconfig.json | 21 - svelte-italic/tsconfig.node.json | 9 - svelte-italic/vite.config.ts | 8 - svelte-katex/.gitignore | 4 - svelte-katex/README.md | 15 - svelte-katex/index.html | 12 - svelte-katex/package.json | 29 - svelte-katex/src/App.svelte | 5 - svelte-katex/src/app.css | 12 - .../editor/examples/katex/editor.svelte | 28 - .../editor/examples/katex/extension.ts | 17 - .../components/editor/examples/katex/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-tex.ts | 60 -- svelte-katex/src/main.ts | 8 - svelte-katex/src/vite-env.d.ts | 2 - svelte-katex/svelte.config.js | 7 - svelte-katex/tsconfig.json | 21 - svelte-katex/tsconfig.node.json | 9 - svelte-katex/vite.config.ts | 8 - svelte-keymap/.gitignore | 4 - svelte-keymap/README.md | 15 - svelte-keymap/index.html | 12 - svelte-keymap/package.json | 28 - svelte-keymap/src/App.svelte | 5 - svelte-keymap/src/app.css | 12 - .../editor/examples/keymap/editor.svelte | 43 -- .../editor/examples/keymap/extension.ts | 8 - .../editor/examples/keymap/index.ts | 1 - .../editor/examples/keymap/toolbar.svelte | 45 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - svelte-keymap/src/main.ts | 8 - svelte-keymap/src/vite-env.d.ts | 2 - svelte-keymap/svelte.config.js | 7 - svelte-keymap/tsconfig.json | 21 - svelte-keymap/tsconfig.node.json | 9 - svelte-keymap/vite.config.ts | 8 - svelte-link-mark-view/.gitignore | 4 - svelte-link-mark-view/README.md | 15 - svelte-link-mark-view/index.html | 12 - svelte-link-mark-view/package.json | 28 - svelte-link-mark-view/src/App.svelte | 5 - svelte-link-mark-view/src/app.css | 12 - .../examples/link-mark-view/editor.svelte | 28 - .../examples/link-mark-view/extension.ts | 17 - .../editor/examples/link-mark-view/index.ts | 1 - .../examples/link-mark-view/link-view.svelte | 50 -- .../sample/sample-doc-link-mark-view.ts | 30 - svelte-link-mark-view/src/main.ts | 8 - svelte-link-mark-view/src/vite-env.d.ts | 2 - svelte-link-mark-view/svelte.config.js | 7 - svelte-link-mark-view/tsconfig.json | 21 - svelte-link-mark-view/tsconfig.node.json | 9 - svelte-link-mark-view/vite.config.ts | 8 - svelte-link/.gitignore | 4 - svelte-link/README.md | 15 - svelte-link/index.html | 12 - svelte-link/package.json | 28 - svelte-link/src/App.svelte | 5 - svelte-link/src/app.css | 12 - .../editor/examples/link/editor.svelte | 30 - .../editor/examples/link/extension.ts | 17 - .../components/editor/examples/link/index.ts | 1 - .../editor/sample/sample-doc-link.ts | 30 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.svelte | 207 ------ svelte-link/src/main.ts | 8 - svelte-link/src/vite-env.d.ts | 2 - svelte-link/svelte.config.js | 7 - svelte-link/tsconfig.json | 21 - svelte-link/tsconfig.node.json | 9 - svelte-link/vite.config.ts | 8 - svelte-list-custom-checkbox/.gitignore | 4 - svelte-list-custom-checkbox/README.md | 15 - svelte-list-custom-checkbox/index.html | 12 - svelte-list-custom-checkbox/package.json | 28 - svelte-list-custom-checkbox/src/App.svelte | 5 - svelte-list-custom-checkbox/src/app.css | 12 - .../list-custom-checkbox/custom-list.css | 75 -- .../list-custom-checkbox/editor.svelte | 31 - .../list-custom-checkbox/extension.ts | 8 - .../examples/list-custom-checkbox/index.ts | 1 - .../sample/sample-doc-list-custom-checkbox.ts | 38 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-list-custom-checkbox/src/main.ts | 8 - svelte-list-custom-checkbox/src/vite-env.d.ts | 2 - svelte-list-custom-checkbox/svelte.config.js | 7 - svelte-list-custom-checkbox/tsconfig.json | 21 - .../tsconfig.node.json | 9 - svelte-list-custom-checkbox/vite.config.ts | 8 - svelte-list/.gitignore | 4 - svelte-list/README.md | 15 - svelte-list/index.html | 12 - svelte-list/package.json | 28 - svelte-list/src/App.svelte | 5 - svelte-list/src/app.css | 12 - .../editor/examples/list/editor.svelte | 30 - .../editor/examples/list/extension.ts | 17 - .../components/editor/examples/list/index.ts | 1 - .../editor/sample/sample-doc-list.ts | 47 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-list/src/main.ts | 8 - svelte-list/src/vite-env.d.ts | 2 - svelte-list/svelte.config.js | 7 - svelte-list/tsconfig.json | 21 - svelte-list/tsconfig.node.json | 9 - svelte-list/vite.config.ts | 8 - svelte-loro/.gitignore | 4 - svelte-loro/README.md | 15 - svelte-loro/index.html | 12 - svelte-loro/package.json | 31 - svelte-loro/src/App.svelte | 5 - svelte-loro/src/app.css | 12 - .../examples/loro/editor-component.svelte | 32 - .../editor/examples/loro/editor.svelte | 55 -- .../editor/examples/loro/extension.ts | 47 -- .../components/editor/examples/loro/index.ts | 1 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-loro/src/main.ts | 8 - svelte-loro/src/vite-env.d.ts | 2 - svelte-loro/svelte.config.js | 7 - svelte-loro/tsconfig.json | 21 - svelte-loro/tsconfig.node.json | 9 - svelte-loro/vite.config.ts | 9 - svelte-mark-rule/.gitignore | 4 - svelte-mark-rule/README.md | 15 - svelte-mark-rule/index.html | 12 - svelte-mark-rule/package.json | 28 - svelte-mark-rule/src/App.svelte | 5 - svelte-mark-rule/src/app.css | 12 - .../editor/examples/mark-rule/editor.svelte | 20 - .../editor/examples/mark-rule/extension.ts | 32 - .../editor/examples/mark-rule/index.ts | 1 - .../editor/examples/mark-rule/issue-link.ts | 32 - svelte-mark-rule/src/main.ts | 8 - svelte-mark-rule/src/vite-env.d.ts | 2 - svelte-mark-rule/svelte.config.js | 7 - svelte-mark-rule/tsconfig.json | 21 - svelte-mark-rule/tsconfig.node.json | 9 - svelte-mark-rule/vite.config.ts | 8 - svelte-minimal/.gitignore | 4 - svelte-minimal/README.md | 15 - svelte-minimal/index.html | 12 - svelte-minimal/package.json | 28 - svelte-minimal/src/App.svelte | 5 - svelte-minimal/src/app.css | 12 - .../editor/examples/minimal/editor.svelte | 15 - .../editor/examples/minimal/index.ts | 1 - svelte-minimal/src/main.ts | 8 - svelte-minimal/src/vite-env.d.ts | 2 - svelte-minimal/svelte.config.js | 7 - svelte-minimal/tsconfig.json | 21 - svelte-minimal/tsconfig.node.json | 9 - svelte-minimal/vite.config.ts | 8 - svelte-page/.gitignore | 4 - svelte-page/README.md | 15 - svelte-page/index.html | 12 - svelte-page/package.json | 28 - svelte-page/src/App.svelte | 5 - svelte-page/src/app.css | 12 - .../editor/examples/page/editor.svelte | 38 - .../editor/examples/page/extension.ts | 9 - .../components/editor/examples/page/index.ts | 1 - .../examples/page/paper-controller.svelte | 143 ---- .../components/editor/examples/page/zoom.css | 9 - .../editor/sample/sample-doc-page.ts | 98 --- svelte-page/src/main.ts | 8 - svelte-page/src/vite-env.d.ts | 2 - svelte-page/svelte.config.js | 7 - svelte-page/tsconfig.json | 21 - svelte-page/tsconfig.node.json | 9 - svelte-page/vite.config.ts | 8 - svelte-placeholder/.gitignore | 4 - svelte-placeholder/README.md | 15 - svelte-placeholder/index.html | 12 - svelte-placeholder/package.json | 28 - svelte-placeholder/src/App.svelte | 5 - svelte-placeholder/src/app.css | 12 - .../editor/examples/placeholder/editor.svelte | 31 - .../editor/examples/placeholder/extension.ts | 12 - .../editor/examples/placeholder/index.ts | 1 - svelte-placeholder/src/main.ts | 8 - svelte-placeholder/src/vite-env.d.ts | 2 - svelte-placeholder/svelte.config.js | 7 - svelte-placeholder/tsconfig.json | 21 - svelte-placeholder/tsconfig.node.json | 9 - svelte-placeholder/vite.config.ts | 8 - svelte-readonly/.gitignore | 4 - svelte-readonly/README.md | 15 - svelte-readonly/index.html | 12 - svelte-readonly/package.json | 28 - svelte-readonly/src/App.svelte | 5 - svelte-readonly/src/app.css | 12 - .../editor/examples/readonly/editor.svelte | 30 - .../editor/examples/readonly/extension.ts | 7 - .../editor/examples/readonly/index.ts | 1 - .../editor/examples/readonly/toolbar.svelte | 27 - .../editor/sample/sample-doc-readonly.ts | 16 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - svelte-readonly/src/main.ts | 8 - svelte-readonly/src/vite-env.d.ts | 2 - svelte-readonly/svelte.config.js | 7 - svelte-readonly/tsconfig.json | 21 - svelte-readonly/tsconfig.node.json | 9 - svelte-readonly/vite.config.ts | 8 - svelte-rtl/.gitignore | 4 - svelte-rtl/README.md | 15 - svelte-rtl/index.html | 12 - svelte-rtl/package.json | 28 - svelte-rtl/src/App.svelte | 5 - svelte-rtl/src/app.css | 12 - .../editor/examples/rtl/editor.svelte | 40 - .../components/editor/examples/rtl/index.ts | 1 - .../editor/sample/sample-doc-rtl.ts | 187 ----- .../editor/sample/sample-uploader.ts | 54 -- .../ui/block-handle/block-handle.svelte | 28 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../ui/drop-indicator/drop-indicator.svelte | 5 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.svelte | 207 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../ui/slash-menu/slash-menu-empty.svelte | 7 - .../ui/slash-menu/slash-menu-item.svelte | 15 - .../editor/ui/slash-menu/slash-menu.svelte | 94 --- .../editor/ui/table-handle/index.ts | 1 - .../ui/table-handle/table-handle.svelte | 182 ----- .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-rtl/src/main.ts | 8 - svelte-rtl/src/vite-env.d.ts | 2 - svelte-rtl/svelte.config.js | 7 - svelte-rtl/tsconfig.json | 21 - svelte-rtl/tsconfig.node.json | 9 - svelte-rtl/vite.config.ts | 8 - svelte-save-html/.gitignore | 4 - svelte-save-html/README.md | 15 - svelte-save-html/index.html | 12 - svelte-save-html/package.json | 28 - svelte-save-html/src/App.svelte | 5 - svelte-save-html/src/app.css | 12 - .../editor/examples/save-html/editor.svelte | 67 -- .../editor/examples/save-html/index.ts | 1 - svelte-save-html/src/main.ts | 8 - svelte-save-html/src/vite-env.d.ts | 2 - svelte-save-html/svelte.config.js | 7 - svelte-save-html/tsconfig.json | 21 - svelte-save-html/tsconfig.node.json | 9 - svelte-save-html/vite.config.ts | 8 - svelte-save-json/.gitignore | 4 - svelte-save-json/README.md | 15 - svelte-save-json/index.html | 12 - svelte-save-json/package.json | 28 - svelte-save-json/src/App.svelte | 5 - svelte-save-json/src/app.css | 12 - .../editor/examples/save-json/editor.svelte | 67 -- .../editor/examples/save-json/index.ts | 1 - svelte-save-json/src/main.ts | 8 - svelte-save-json/src/vite-env.d.ts | 2 - svelte-save-json/svelte.config.js | 7 - svelte-save-json/tsconfig.json | 21 - svelte-save-json/tsconfig.node.json | 9 - svelte-save-json/vite.config.ts | 8 - svelte-save-markdown/.gitignore | 4 - svelte-save-markdown/README.md | 15 - svelte-save-markdown/index.html | 12 - svelte-save-markdown/package.json | 35 - svelte-save-markdown/src/App.svelte | 5 - svelte-save-markdown/src/app.css | 12 - .../examples/save-markdown/editor.svelte | 71 -- .../editor/examples/save-markdown/index.ts | 1 - .../editor/examples/save-markdown/markdown.ts | 26 - svelte-save-markdown/src/main.ts | 8 - svelte-save-markdown/src/vite-env.d.ts | 2 - svelte-save-markdown/svelte.config.js | 7 - svelte-save-markdown/tsconfig.json | 21 - svelte-save-markdown/tsconfig.node.json | 9 - svelte-save-markdown/vite.config.ts | 8 - svelte-search/.gitignore | 4 - svelte-search/README.md | 15 - svelte-search/index.html | 12 - svelte-search/package.json | 28 - svelte-search/src/App.svelte | 5 - svelte-search/src/app.css | 12 - .../editor/examples/search/editor.svelte | 31 - .../editor/examples/search/extension.ts | 9 - .../editor/examples/search/index.ts | 1 - .../editor/sample/sample-doc-search.ts | 79 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../src/components/editor/ui/search/index.ts | 1 - .../components/editor/ui/search/search.svelte | 168 ----- svelte-search/src/main.ts | 8 - svelte-search/src/vite-env.d.ts | 2 - svelte-search/svelte.config.js | 7 - svelte-search/tsconfig.json | 21 - svelte-search/tsconfig.node.json | 9 - svelte-search/vite.config.ts | 8 - svelte-slash-menu/.gitignore | 4 - svelte-slash-menu/README.md | 15 - svelte-slash-menu/index.html | 12 - svelte-slash-menu/package.json | 28 - svelte-slash-menu/src/App.svelte | 5 - svelte-slash-menu/src/app.css | 12 - .../editor/examples/slash-menu/editor.svelte | 23 - .../editor/examples/slash-menu/extension.ts | 12 - .../editor/examples/slash-menu/index.ts | 1 - .../components/editor/ui/slash-menu/index.ts | 1 - .../ui/slash-menu/slash-menu-empty.svelte | 7 - .../ui/slash-menu/slash-menu-item.svelte | 15 - .../editor/ui/slash-menu/slash-menu.svelte | 94 --- svelte-slash-menu/src/main.ts | 8 - svelte-slash-menu/src/vite-env.d.ts | 2 - svelte-slash-menu/svelte.config.js | 7 - svelte-slash-menu/tsconfig.json | 21 - svelte-slash-menu/tsconfig.node.json | 9 - svelte-slash-menu/vite.config.ts | 8 - svelte-strike/.gitignore | 4 - svelte-strike/README.md | 15 - svelte-strike/index.html | 12 - svelte-strike/package.json | 28 - svelte-strike/src/App.svelte | 5 - svelte-strike/src/app.css | 12 - .../editor/examples/strike/editor.svelte | 30 - .../editor/examples/strike/extension.ts | 17 - .../editor/examples/strike/index.ts | 1 - .../editor/examples/strike/toolbar.svelte | 30 - .../editor/sample/sample-doc-strike.ts | 30 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - svelte-strike/src/main.ts | 8 - svelte-strike/src/vite-env.d.ts | 2 - svelte-strike/svelte.config.js | 7 - svelte-strike/tsconfig.json | 21 - svelte-strike/tsconfig.node.json | 9 - svelte-strike/vite.config.ts | 8 - svelte-sub-sup/.gitignore | 4 - svelte-sub-sup/README.md | 15 - svelte-sub-sup/index.html | 12 - svelte-sub-sup/package.json | 28 - svelte-sub-sup/src/App.svelte | 5 - svelte-sub-sup/src/app.css | 12 - .../editor/examples/sub-sup/editor.svelte | 30 - .../editor/examples/sub-sup/extension.ts | 32 - .../editor/examples/sub-sup/index.ts | 1 - .../editor/examples/sub-sup/toolbar.svelte | 42 -- .../editor/sample/sample-doc-sub-sup.ts | 42 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - svelte-sub-sup/src/main.ts | 8 - svelte-sub-sup/src/vite-env.d.ts | 2 - svelte-sub-sup/svelte.config.js | 7 - svelte-sub-sup/tsconfig.json | 21 - svelte-sub-sup/tsconfig.node.json | 9 - svelte-sub-sup/vite.config.ts | 8 - svelte-table/.gitignore | 4 - svelte-table/README.md | 15 - svelte-table/index.html | 12 - svelte-table/package.json | 28 - svelte-table/src/App.svelte | 5 - svelte-table/src/app.css | 12 - .../editor/examples/table/editor.svelte | 30 - .../editor/examples/table/extension.ts | 20 - .../components/editor/examples/table/index.ts | 1 - .../editor/sample/sample-doc-table.ts | 174 ----- .../editor/ui/table-handle/index.ts | 1 - .../ui/table-handle/table-handle.svelte | 182 ----- svelte-table/src/main.ts | 8 - svelte-table/src/vite-env.d.ts | 2 - svelte-table/svelte.config.js | 7 - svelte-table/tsconfig.json | 21 - svelte-table/tsconfig.node.json | 9 - svelte-table/vite.config.ts | 8 - svelte-text-align/.gitignore | 4 - svelte-text-align/README.md | 15 - svelte-text-align/index.html | 12 - svelte-text-align/package.json | 28 - svelte-text-align/src/App.svelte | 5 - svelte-text-align/src/app.css | 12 - .../editor/examples/text-align/editor.svelte | 30 - .../editor/examples/text-align/extension.ts | 12 - .../editor/examples/text-align/index.ts | 1 - .../editor/examples/text-align/toolbar.svelte | 76 -- .../editor/sample/sample-doc-text-align.ts | 56 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - svelte-text-align/src/main.ts | 8 - svelte-text-align/src/vite-env.d.ts | 2 - svelte-text-align/svelte.config.js | 7 - svelte-text-align/tsconfig.json | 21 - svelte-text-align/tsconfig.node.json | 9 - svelte-text-align/vite.config.ts | 8 - svelte-text-color/.gitignore | 4 - svelte-text-color/README.md | 15 - svelte-text-color/index.html | 12 - svelte-text-color/package.json | 28 - svelte-text-color/src/App.svelte | 5 - svelte-text-color/src/app.css | 12 - .../editor/examples/text-color/editor.svelte | 30 - .../editor/examples/text-color/extension.ts | 14 - .../editor/examples/text-color/index.ts | 1 - .../examples/text-color/inline-menu.svelte | 127 ---- .../editor/sample/sample-doc-text-color.ts | 120 --- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - svelte-text-color/src/main.ts | 8 - svelte-text-color/src/vite-env.d.ts | 2 - svelte-text-color/svelte.config.js | 7 - svelte-text-color/tsconfig.json | 21 - svelte-text-color/tsconfig.node.json | 9 - svelte-text-color/vite.config.ts | 8 - svelte-toolbar/.gitignore | 4 - svelte-toolbar/README.md | 15 - svelte-toolbar/index.html | 12 - svelte-toolbar/package.json | 28 - svelte-toolbar/src/App.svelte | 5 - svelte-toolbar/src/app.css | 12 - .../editor/examples/toolbar/editor.svelte | 24 - .../editor/examples/toolbar/extension.ts | 8 - .../editor/examples/toolbar/index.ts | 1 - .../editor/sample/sample-uploader.ts | 54 -- .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-toolbar/src/main.ts | 8 - svelte-toolbar/src/vite-env.d.ts | 2 - svelte-toolbar/svelte.config.js | 7 - svelte-toolbar/tsconfig.json | 21 - svelte-toolbar/tsconfig.node.json | 9 - svelte-toolbar/vite.config.ts | 8 - svelte-typography/.gitignore | 4 - svelte-typography/README.md | 15 - svelte-typography/index.html | 12 - svelte-typography/package.json | 29 - svelte-typography/src/App.svelte | 5 - svelte-typography/src/app.css | 12 - .../editor/examples/typography/editor.svelte | 32 - .../editor/examples/typography/extension.ts | 17 - .../editor/examples/typography/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-typography.ts | 693 ------------------ .../ui/block-handle/block-handle.svelte | 28 - .../editor/ui/block-handle/index.ts | 1 - .../ui/drop-indicator/drop-indicator.svelte | 5 - .../editor/ui/drop-indicator/index.ts | 1 - svelte-typography/src/main.ts | 8 - svelte-typography/src/vite-env.d.ts | 2 - svelte-typography/svelte.config.js | 7 - svelte-typography/tsconfig.json | 21 - svelte-typography/tsconfig.node.json | 9 - svelte-typography/vite.config.ts | 8 - svelte-underline/.gitignore | 4 - svelte-underline/README.md | 15 - svelte-underline/index.html | 12 - svelte-underline/package.json | 28 - svelte-underline/src/App.svelte | 5 - svelte-underline/src/app.css | 12 - .../editor/examples/underline/editor.svelte | 30 - .../editor/examples/underline/extension.ts | 17 - .../editor/examples/underline/index.ts | 1 - .../editor/sample/sample-doc-underline.ts | 30 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-underline/src/main.ts | 8 - svelte-underline/src/vite-env.d.ts | 2 - svelte-underline/svelte.config.js | 7 - svelte-underline/tsconfig.json | 21 - svelte-underline/tsconfig.node.json | 9 - svelte-underline/vite.config.ts | 8 - svelte-unmount/.gitignore | 4 - svelte-unmount/README.md | 15 - svelte-unmount/index.html | 12 - svelte-unmount/package.json | 28 - svelte-unmount/src/App.svelte | 5 - svelte-unmount/src/app.css | 12 - .../examples/unmount/editor-component.svelte | 28 - .../editor/examples/unmount/editor.svelte | 37 - .../unmount/extension-component.svelte | 13 - .../editor/examples/unmount/index.ts | 1 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.svelte | 207 ------ svelte-unmount/src/main.ts | 8 - svelte-unmount/src/vite-env.d.ts | 2 - svelte-unmount/svelte.config.js | 7 - svelte-unmount/tsconfig.json | 21 - svelte-unmount/tsconfig.node.json | 9 - svelte-unmount/vite.config.ts | 8 - svelte-user-menu-dynamic/.gitignore | 4 - svelte-user-menu-dynamic/README.md | 15 - svelte-user-menu-dynamic/index.html | 12 - svelte-user-menu-dynamic/package.json | 28 - svelte-user-menu-dynamic/src/App.svelte | 5 - svelte-user-menu-dynamic/src/app.css | 12 - .../examples/user-menu-dynamic/editor.svelte | 22 - .../examples/user-menu-dynamic/extension.ts | 16 - .../examples/user-menu-dynamic/index.ts | 1 - .../use-user-query.svelte.ts | 37 - .../user-menu-dynamic.svelte | 25 - .../editor/sample/sample-query-users.ts | 40 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.svelte | 70 -- svelte-user-menu-dynamic/src/main.ts | 8 - svelte-user-menu-dynamic/src/vite-env.d.ts | 2 - svelte-user-menu-dynamic/svelte.config.js | 7 - svelte-user-menu-dynamic/tsconfig.json | 21 - svelte-user-menu-dynamic/tsconfig.node.json | 9 - svelte-user-menu-dynamic/vite.config.ts | 8 - svelte-user-menu/.gitignore | 4 - svelte-user-menu/README.md | 15 - svelte-user-menu/index.html | 12 - svelte-user-menu/package.json | 28 - svelte-user-menu/src/App.svelte | 5 - svelte-user-menu/src/app.css | 12 - .../editor/examples/user-menu/editor.svelte | 27 - .../editor/examples/user-menu/extension.ts | 16 - .../editor/examples/user-menu/index.ts | 1 - .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.svelte | 53 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.svelte | 70 -- svelte-user-menu/src/main.ts | 8 - svelte-user-menu/src/vite-env.d.ts | 2 - svelte-user-menu/svelte.config.js | 7 - svelte-user-menu/tsconfig.json | 21 - svelte-user-menu/tsconfig.node.json | 9 - svelte-user-menu/vite.config.ts | 8 - svelte-word-counter/.gitignore | 4 - svelte-word-counter/README.md | 15 - svelte-word-counter/index.html | 12 - svelte-word-counter/package.json | 28 - svelte-word-counter/src/App.svelte | 5 - svelte-word-counter/src/app.css | 12 - .../examples/word-counter/editor.svelte | 30 - .../editor/examples/word-counter/extension.ts | 8 - .../editor/examples/word-counter/index.ts | 1 - .../editor/sample/sample-doc-word-counter.ts | 16 - .../editor/ui/word-counter/index.ts | 1 - .../ui/word-counter/word-counter.svelte | 20 - svelte-word-counter/src/main.ts | 8 - svelte-word-counter/src/vite-env.d.ts | 2 - svelte-word-counter/svelte.config.js | 7 - svelte-word-counter/tsconfig.json | 21 - svelte-word-counter/tsconfig.node.json | 9 - svelte-word-counter/vite.config.ts | 8 - svelte-yjs/.gitignore | 4 - svelte-yjs/README.md | 15 - svelte-yjs/index.html | 12 - svelte-yjs/package.json | 32 - svelte-yjs/src/App.svelte | 5 - svelte-yjs/src/app.css | 12 - .../examples/yjs/editor-component.svelte | 33 - .../editor/examples/yjs/editor.svelte | 27 - .../editor/examples/yjs/extension.ts | 48 -- .../components/editor/examples/yjs/index.ts | 1 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- svelte-yjs/src/main.ts | 8 - svelte-yjs/src/vite-env.d.ts | 2 - svelte-yjs/svelte.config.js | 7 - svelte-yjs/tsconfig.json | 21 - svelte-yjs/tsconfig.node.json | 9 - svelte-yjs/vite.config.ts | 8 - sveltekit-full/.gitignore | 4 - sveltekit-full/README.md | 15 - sveltekit-full/package.json | 31 - sveltekit-full/src/app.css | 12 - sveltekit-full/src/app.d.ts | 13 - sveltekit-full/src/app.html | 12 - .../editor/examples/full/editor.svelte | 47 -- .../editor/examples/full/extension.ts | 34 - .../components/editor/examples/full/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-full.ts | 442 ----------- .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/sample/sample-user-data.ts | 54 -- .../ui/block-handle/block-handle.svelte | 28 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.svelte | 39 - .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.svelte | 40 - .../editor/ui/code-block-view/index.ts | 15 - .../ui/drop-indicator/drop-indicator.svelte | 5 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.svelte | 121 --- .../editor/ui/image-upload-popover/index.ts | 1 - .../editor/ui/image-view/image-view.svelte | 97 --- .../components/editor/ui/image-view/index.ts | 14 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.svelte | 207 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../ui/slash-menu/slash-menu-empty.svelte | 7 - .../ui/slash-menu/slash-menu-item.svelte | 15 - .../editor/ui/slash-menu/slash-menu.svelte | 94 --- .../editor/ui/table-handle/index.ts | 1 - .../ui/table-handle/table-handle.svelte | 182 ----- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.svelte | 53 -- .../src/components/editor/ui/toolbar/index.ts | 1 - .../editor/ui/toolbar/toolbar.svelte | 365 --------- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.svelte | 70 -- sveltekit-full/src/lib/App.svelte | 5 - .../src/lib/client-only-editor.svelte | 14 - sveltekit-full/src/lib/editor.svelte | 1 - sveltekit-full/src/routes/+layout.svelte | 5 - sveltekit-full/src/routes/+page.svelte | 7 - sveltekit-full/static/favicon.png | Bin 1571 -> 0 bytes sveltekit-full/svelte.config.js | 18 - sveltekit-full/tsconfig.json | 19 - sveltekit-full/vite.config.ts | 7 - vanilla-minimal/.gitignore | 4 - vanilla-minimal/README.md | 15 - vanilla-minimal/index.html | 11 - vanilla-minimal/package.json | 23 - vanilla-minimal/src/app.css | 12 - .../editor/examples/minimal/editor.ts | 22 - .../editor/examples/minimal/index.ts | 1 - vanilla-minimal/src/editor.ts | 5 - vanilla-minimal/src/main.ts | 11 - vanilla-minimal/tsconfig.json | 26 - vanilla-minimal/vite.config.ts | 6 - vanilla-slash-menu/.gitignore | 4 - vanilla-slash-menu/README.md | 15 - vanilla-slash-menu/index.html | 11 - vanilla-slash-menu/package.json | 23 - vanilla-slash-menu/src/app.css | 12 - .../editor/examples/slash-menu/editor.ts | 39 - .../editor/examples/slash-menu/extension.ts | 12 - .../editor/examples/slash-menu/index.ts | 1 - .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.ts | 17 - .../editor/ui/slash-menu/slash-menu-item.ts | 29 - .../editor/ui/slash-menu/slash-menu.ts | 131 ---- vanilla-slash-menu/src/editor.ts | 5 - vanilla-slash-menu/src/main.ts | 11 - vanilla-slash-menu/tsconfig.json | 26 - vanilla-slash-menu/vite.config.ts | 6 - vue-block-handle/.gitignore | 4 - vue-block-handle/README.md | 15 - vue-block-handle/index.html | 12 - vue-block-handle/package.json | 27 - vue-block-handle/src/App.vue | 7 - vue-block-handle/src/app.css | 12 - .../editor/examples/block-handle/editor.vue | 38 - .../editor/examples/block-handle/extension.ts | 10 - .../editor/examples/block-handle/index.ts | 1 - .../editor/sample/sample-doc-block-handle.ts | 323 -------- .../editor/ui/block-handle/block-handle.vue | 39 - .../editor/ui/block-handle/index.ts | 1 - .../ui/code-block-view/code-block-view.vue | 41 -- .../editor/ui/code-block-view/index.ts | 12 - .../ui/drop-indicator/drop-indicator.vue | 7 - .../editor/ui/drop-indicator/index.ts | 1 - vue-block-handle/src/main.ts | 5 - vue-block-handle/tsconfig.app.json | 16 - vue-block-handle/tsconfig.json | 7 - vue-block-handle/tsconfig.node.json | 26 - vue-block-handle/vite.config.ts | 8 - vue-blockquote/.gitignore | 4 - vue-blockquote/README.md | 15 - vue-blockquote/index.html | 12 - vue-blockquote/package.json | 27 - vue-blockquote/src/App.vue | 7 - vue-blockquote/src/app.css | 12 - .../editor/examples/blockquote/editor.vue | 30 - .../editor/examples/blockquote/extension.ts | 17 - .../editor/examples/blockquote/index.ts | 1 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-blockquote/src/main.ts | 5 - vue-blockquote/tsconfig.app.json | 16 - vue-blockquote/tsconfig.json | 7 - vue-blockquote/tsconfig.node.json | 26 - vue-blockquote/vite.config.ts | 8 - vue-bold/.gitignore | 4 - vue-bold/README.md | 15 - vue-bold/index.html | 12 - vue-bold/package.json | 27 - vue-bold/src/App.vue | 7 - vue-bold/src/app.css | 12 - .../editor/examples/bold/editor.vue | 36 - .../editor/examples/bold/extension.ts | 17 - .../components/editor/examples/bold/index.ts | 1 - .../editor/sample/sample-doc-bold.ts | 44 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-bold/src/main.ts | 5 - vue-bold/tsconfig.app.json | 16 - vue-bold/tsconfig.json | 7 - vue-bold/tsconfig.node.json | 26 - vue-bold/vite.config.ts | 8 - vue-change-tracking/.gitignore | 4 - vue-change-tracking/README.md | 15 - vue-change-tracking/index.html | 12 - vue-change-tracking/package.json | 27 - vue-change-tracking/src/App.vue | 7 - vue-change-tracking/src/app.css | 12 - .../examples/change-tracking/editor-diff.vue | 32 - .../examples/change-tracking/editor-main.vue | 40 - .../examples/change-tracking/editor.vue | 71 -- .../editor/examples/change-tracking/index.ts | 1 - vue-change-tracking/src/main.ts | 5 - vue-change-tracking/tsconfig.app.json | 16 - vue-change-tracking/tsconfig.json | 7 - vue-change-tracking/tsconfig.node.json | 26 - vue-change-tracking/vite.config.ts | 8 - vue-code-block-themes/.gitignore | 4 - vue-code-block-themes/README.md | 15 - vue-code-block-themes/index.html | 12 - vue-code-block-themes/package.json | 27 - vue-code-block-themes/src/App.vue | 7 - vue-code-block-themes/src/app.css | 12 - .../examples/code-block-themes/editor.vue | 39 - .../examples/code-block-themes/extension.ts | 10 - .../examples/code-block-themes/index.ts | 1 - .../code-block-themes/theme-selector.vue | 33 - .../examples/code-block-themes/toolbar.vue | 11 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../ui/code-block-view/code-block-view.vue | 41 -- .../editor/ui/code-block-view/index.ts | 12 - vue-code-block-themes/src/main.ts | 5 - vue-code-block-themes/tsconfig.app.json | 16 - vue-code-block-themes/tsconfig.json | 7 - vue-code-block-themes/tsconfig.node.json | 26 - vue-code-block-themes/vite.config.ts | 8 - vue-code-block/.gitignore | 4 - vue-code-block/README.md | 15 - vue-code-block/index.html | 12 - vue-code-block/package.json | 27 - vue-code-block/src/App.vue | 7 - vue-code-block/src/app.css | 12 - .../editor/examples/code-block/editor.vue | 39 - .../editor/examples/code-block/extension.ts | 24 - .../editor/examples/code-block/index.ts | 1 - .../editor/sample/sample-doc-code-block.ts | 50 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.vue | 41 -- .../editor/ui/code-block-view/index.ts | 12 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-code-block/src/main.ts | 5 - vue-code-block/tsconfig.app.json | 16 - vue-code-block/tsconfig.json | 7 - vue-code-block/tsconfig.node.json | 26 - vue-code-block/vite.config.ts | 8 - vue-code/.gitignore | 4 - vue-code/README.md | 15 - vue-code/index.html | 12 - vue-code/package.json | 27 - vue-code/src/App.vue | 7 - vue-code/src/app.css | 12 - .../editor/examples/code/editor.vue | 36 - .../editor/examples/code/extension.ts | 17 - .../components/editor/examples/code/index.ts | 1 - .../editor/sample/sample-doc-code.ts | 30 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-code/src/main.ts | 5 - vue-code/tsconfig.app.json | 16 - vue-code/tsconfig.json | 7 - vue-code/tsconfig.node.json | 26 - vue-code/vite.config.ts | 8 - vue-drop-cursor/.gitignore | 4 - vue-drop-cursor/README.md | 15 - vue-drop-cursor/index.html | 12 - vue-drop-cursor/package.json | 27 - vue-drop-cursor/src/App.vue | 7 - vue-drop-cursor/src/app.css | 12 - .../editor/examples/drop-cursor/editor.vue | 34 - .../editor/examples/drop-cursor/extension.ts | 23 - .../editor/examples/drop-cursor/index.ts | 1 - .../editor/sample/sample-doc-drop-cursor.ts | 40 - vue-drop-cursor/src/main.ts | 5 - vue-drop-cursor/tsconfig.app.json | 16 - vue-drop-cursor/tsconfig.json | 7 - vue-drop-cursor/tsconfig.node.json | 26 - vue-drop-cursor/vite.config.ts | 8 - vue-emoji-rules/.gitignore | 4 - vue-emoji-rules/README.md | 15 - vue-emoji-rules/index.html | 12 - vue-emoji-rules/package.json | 27 - vue-emoji-rules/src/App.vue | 7 - vue-emoji-rules/src/app.css | 12 - .../editor/examples/emoji-rules/editor.vue | 27 - .../editor/examples/emoji-rules/emoji.ts | 15 - .../editor/examples/emoji-rules/extension.ts | 15 - .../editor/examples/emoji-rules/index.ts | 1 - vue-emoji-rules/src/main.ts | 5 - vue-emoji-rules/tsconfig.app.json | 16 - vue-emoji-rules/tsconfig.json | 7 - vue-emoji-rules/tsconfig.node.json | 26 - vue-emoji-rules/vite.config.ts | 8 - vue-full/.gitignore | 4 - vue-full/README.md | 15 - vue-full/index.html | 12 - vue-full/package.json | 28 - vue-full/src/App.vue | 7 - vue-full/src/app.css | 12 - .../editor/examples/full/editor.vue | 53 -- .../editor/examples/full/extension.ts | 34 - .../components/editor/examples/full/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-full.ts | 442 ----------- .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/sample/sample-user-data.ts | 54 -- .../editor/ui/block-handle/block-handle.vue | 39 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/code-block-view/code-block-view.vue | 41 -- .../editor/ui/code-block-view/index.ts | 12 - .../ui/drop-indicator/drop-indicator.vue | 7 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../editor/ui/image-view/image-view.vue | 97 --- .../components/editor/ui/image-view/index.ts | 11 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.vue | 219 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.vue | 11 - .../editor/ui/slash-menu/slash-menu-item.vue | 24 - .../editor/ui/slash-menu/slash-menu.vue | 106 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.vue | 204 ------ .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.vue | 59 -- .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.vue | 74 -- vue-full/src/main.ts | 5 - vue-full/tsconfig.app.json | 16 - vue-full/tsconfig.json | 7 - vue-full/tsconfig.node.json | 26 - vue-full/vite.config.ts | 8 - vue-gap-cursor/.gitignore | 4 - vue-gap-cursor/README.md | 15 - vue-gap-cursor/index.html | 12 - vue-gap-cursor/package.json | 27 - vue-gap-cursor/src/App.vue | 7 - vue-gap-cursor/src/app.css | 12 - .../editor/examples/gap-cursor/editor.vue | 34 - .../editor/examples/gap-cursor/extension.ts | 19 - .../editor/examples/gap-cursor/index.ts | 1 - .../editor/sample/sample-doc-gap-cursor.ts | 28 - vue-gap-cursor/src/main.ts | 5 - vue-gap-cursor/tsconfig.app.json | 16 - vue-gap-cursor/tsconfig.json | 7 - vue-gap-cursor/tsconfig.node.json | 26 - vue-gap-cursor/vite.config.ts | 8 - vue-hard-break/.gitignore | 4 - vue-hard-break/README.md | 15 - vue-hard-break/index.html | 12 - vue-hard-break/package.json | 27 - vue-hard-break/src/App.vue | 7 - vue-hard-break/src/app.css | 12 - .../editor/examples/hard-break/editor.vue | 36 - .../editor/examples/hard-break/extension.ts | 17 - .../editor/examples/hard-break/index.ts | 1 - .../editor/examples/hard-break/toolbar.vue | 33 - .../editor/sample/sample-doc-hard-break.ts | 68 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - vue-hard-break/src/main.ts | 5 - vue-hard-break/tsconfig.app.json | 16 - vue-hard-break/tsconfig.json | 7 - vue-hard-break/tsconfig.node.json | 26 - vue-hard-break/vite.config.ts | 8 - vue-heading/.gitignore | 4 - vue-heading/README.md | 15 - vue-heading/index.html | 12 - vue-heading/package.json | 27 - vue-heading/src/App.vue | 7 - vue-heading/src/app.css | 12 - .../editor/examples/heading/editor.vue | 36 - .../editor/examples/heading/extension.ts | 17 - .../editor/examples/heading/index.ts | 1 - .../editor/sample/sample-doc-heading.ts | 23 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-heading/src/main.ts | 5 - vue-heading/tsconfig.app.json | 16 - vue-heading/tsconfig.json | 7 - vue-heading/tsconfig.node.json | 26 - vue-heading/vite.config.ts | 8 - vue-highlight/.gitignore | 4 - vue-highlight/README.md | 15 - vue-highlight/index.html | 12 - vue-highlight/package.json | 27 - vue-highlight/src/App.vue | 7 - vue-highlight/src/app.css | 12 - .../editor/examples/highlight/editor.vue | 36 - .../editor/examples/highlight/extension.ts | 17 - .../editor/examples/highlight/index.ts | 1 - .../editor/examples/highlight/toolbar.vue | 34 - .../editor/sample/sample-doc-highlight.ts | 30 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - vue-highlight/src/main.ts | 5 - vue-highlight/tsconfig.app.json | 16 - vue-highlight/tsconfig.json | 7 - vue-highlight/tsconfig.node.json | 26 - vue-highlight/vite.config.ts | 8 - vue-horizontal-rule/.gitignore | 4 - vue-horizontal-rule/README.md | 15 - vue-horizontal-rule/index.html | 12 - vue-horizontal-rule/package.json | 27 - vue-horizontal-rule/src/App.vue | 7 - vue-horizontal-rule/src/app.css | 12 - .../examples/horizontal-rule/editor.vue | 30 - .../examples/horizontal-rule/extension.ts | 17 - .../editor/examples/horizontal-rule/index.ts | 1 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-horizontal-rule/src/main.ts | 5 - vue-horizontal-rule/tsconfig.app.json | 16 - vue-horizontal-rule/tsconfig.json | 7 - vue-horizontal-rule/tsconfig.node.json | 26 - vue-horizontal-rule/vite.config.ts | 8 - vue-image-view/.gitignore | 4 - vue-image-view/README.md | 15 - vue-image-view/index.html | 12 - vue-image-view/package.json | 27 - vue-image-view/src/App.vue | 7 - vue-image-view/src/app.css | 12 - .../editor/examples/image-view/editor.vue | 34 - .../editor/examples/image-view/extension.ts | 18 - .../editor/examples/image-view/index.ts | 1 - .../editor/sample/sample-doc-image.ts | 32 - .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/image-view/image-view.vue | 97 --- .../components/editor/ui/image-view/index.ts | 11 - vue-image-view/src/main.ts | 5 - vue-image-view/tsconfig.app.json | 16 - vue-image-view/tsconfig.json | 7 - vue-image-view/tsconfig.node.json | 26 - vue-image-view/vite.config.ts | 8 - vue-inline-menu/.gitignore | 4 - vue-inline-menu/README.md | 15 - vue-inline-menu/index.html | 12 - vue-inline-menu/package.json | 27 - vue-inline-menu/src/App.vue | 7 - vue-inline-menu/src/app.css | 12 - .../editor/examples/inline-menu/editor.vue | 36 - .../editor/examples/inline-menu/extension.ts | 7 - .../editor/examples/inline-menu/index.ts | 1 - .../editor/sample/sample-doc-inline-menu.ts | 33 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.vue | 219 ------ vue-inline-menu/src/main.ts | 5 - vue-inline-menu/tsconfig.app.json | 16 - vue-inline-menu/tsconfig.json | 7 - vue-inline-menu/tsconfig.node.json | 26 - vue-inline-menu/vite.config.ts | 8 - vue-italic/.gitignore | 4 - vue-italic/README.md | 15 - vue-italic/index.html | 12 - vue-italic/package.json | 27 - vue-italic/src/App.vue | 7 - vue-italic/src/app.css | 12 - .../editor/examples/italic/editor.vue | 36 - .../editor/examples/italic/extension.ts | 17 - .../editor/examples/italic/index.ts | 1 - .../editor/sample/sample-doc-italic.ts | 44 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-italic/src/main.ts | 5 - vue-italic/tsconfig.app.json | 16 - vue-italic/tsconfig.json | 7 - vue-italic/tsconfig.node.json | 26 - vue-italic/vite.config.ts | 8 - vue-katex/.gitignore | 4 - vue-katex/README.md | 15 - vue-katex/index.html | 12 - vue-katex/package.json | 28 - vue-katex/src/App.vue | 7 - vue-katex/src/app.css | 12 - .../editor/examples/katex/editor.vue | 34 - .../editor/examples/katex/extension.ts | 17 - .../components/editor/examples/katex/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-tex.ts | 60 -- vue-katex/src/main.ts | 5 - vue-katex/tsconfig.app.json | 16 - vue-katex/tsconfig.json | 7 - vue-katex/tsconfig.node.json | 26 - vue-katex/vite.config.ts | 8 - vue-keymap/.gitignore | 4 - vue-keymap/README.md | 15 - vue-keymap/index.html | 12 - vue-keymap/package.json | 27 - vue-keymap/src/App.vue | 7 - vue-keymap/src/app.css | 12 - .../editor/examples/keymap/editor.vue | 49 -- .../editor/examples/keymap/extension.ts | 8 - .../editor/examples/keymap/index.ts | 1 - .../editor/examples/keymap/toolbar.vue | 38 - .../examples/keymap/use-submit-keymap.ts | 19 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - vue-keymap/src/main.ts | 5 - vue-keymap/tsconfig.app.json | 16 - vue-keymap/tsconfig.json | 7 - vue-keymap/tsconfig.node.json | 26 - vue-keymap/vite.config.ts | 8 - vue-link-mark-view/.gitignore | 4 - vue-link-mark-view/README.md | 15 - vue-link-mark-view/index.html | 12 - vue-link-mark-view/package.json | 27 - vue-link-mark-view/src/App.vue | 7 - vue-link-mark-view/src/app.css | 12 - .../editor/examples/link-mark-view/editor.vue | 34 - .../examples/link-mark-view/extension.ts | 17 - .../editor/examples/link-mark-view/index.ts | 1 - .../examples/link-mark-view/link-view.vue | 48 -- .../sample/sample-doc-link-mark-view.ts | 30 - vue-link-mark-view/src/main.ts | 5 - vue-link-mark-view/tsconfig.app.json | 16 - vue-link-mark-view/tsconfig.json | 7 - vue-link-mark-view/tsconfig.node.json | 26 - vue-link-mark-view/vite.config.ts | 8 - vue-link/.gitignore | 4 - vue-link/README.md | 15 - vue-link/index.html | 12 - vue-link/package.json | 27 - vue-link/src/App.vue | 7 - vue-link/src/app.css | 12 - .../editor/examples/link/editor.vue | 36 - .../editor/examples/link/extension.ts | 17 - .../components/editor/examples/link/index.ts | 1 - .../editor/sample/sample-doc-link.ts | 30 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.vue | 219 ------ vue-link/src/main.ts | 5 - vue-link/tsconfig.app.json | 16 - vue-link/tsconfig.json | 7 - vue-link/tsconfig.node.json | 26 - vue-link/vite.config.ts | 8 - vue-list-custom-checkbox/.gitignore | 4 - vue-list-custom-checkbox/README.md | 15 - vue-list-custom-checkbox/index.html | 12 - vue-list-custom-checkbox/package.json | 27 - vue-list-custom-checkbox/src/App.vue | 7 - vue-list-custom-checkbox/src/app.css | 12 - .../list-custom-checkbox/custom-list.css | 75 -- .../examples/list-custom-checkbox/editor.vue | 41 -- .../list-custom-checkbox/extension.ts | 8 - .../examples/list-custom-checkbox/index.ts | 1 - .../sample/sample-doc-list-custom-checkbox.ts | 38 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-list-custom-checkbox/src/main.ts | 5 - vue-list-custom-checkbox/tsconfig.app.json | 16 - vue-list-custom-checkbox/tsconfig.json | 7 - vue-list-custom-checkbox/tsconfig.node.json | 26 - vue-list-custom-checkbox/vite.config.ts | 8 - vue-list/.gitignore | 4 - vue-list/README.md | 15 - vue-list/index.html | 12 - vue-list/package.json | 27 - vue-list/src/App.vue | 7 - vue-list/src/app.css | 12 - .../editor/examples/list/editor.vue | 39 - .../editor/examples/list/extension.ts | 17 - .../components/editor/examples/list/index.ts | 1 - .../editor/sample/sample-doc-list.ts | 47 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-list/src/main.ts | 5 - vue-list/tsconfig.app.json | 16 - vue-list/tsconfig.json | 7 - vue-list/tsconfig.node.json | 26 - vue-list/vite.config.ts | 8 - vue-loro/.gitignore | 4 - vue-loro/README.md | 15 - vue-loro/index.html | 12 - vue-loro/package.json | 30 - vue-loro/src/App.vue | 7 - vue-loro/src/app.css | 12 - .../editor/examples/loro/editor-component.vue | 37 - .../editor/examples/loro/editor.vue | 56 -- .../editor/examples/loro/extension.ts | 47 -- .../components/editor/examples/loro/index.ts | 1 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-loro/src/main.ts | 5 - vue-loro/tsconfig.app.json | 16 - vue-loro/tsconfig.json | 7 - vue-loro/tsconfig.node.json | 26 - vue-loro/vite.config.ts | 9 - vue-mark-rule/.gitignore | 4 - vue-mark-rule/README.md | 15 - vue-mark-rule/index.html | 12 - vue-mark-rule/package.json | 27 - vue-mark-rule/src/App.vue | 7 - vue-mark-rule/src/app.css | 12 - .../editor/examples/mark-rule/editor.vue | 27 - .../editor/examples/mark-rule/extension.ts | 32 - .../editor/examples/mark-rule/index.ts | 1 - .../editor/examples/mark-rule/issue-link.ts | 32 - vue-mark-rule/src/main.ts | 5 - vue-mark-rule/tsconfig.app.json | 16 - vue-mark-rule/tsconfig.json | 7 - vue-mark-rule/tsconfig.node.json | 26 - vue-mark-rule/vite.config.ts | 8 - vue-minimal/.gitignore | 4 - vue-minimal/README.md | 15 - vue-minimal/index.html | 12 - vue-minimal/package.json | 27 - vue-minimal/src/App.vue | 7 - vue-minimal/src/app.css | 12 - .../editor/examples/minimal/editor.vue | 20 - .../editor/examples/minimal/index.ts | 1 - vue-minimal/src/main.ts | 5 - vue-minimal/tsconfig.app.json | 16 - vue-minimal/tsconfig.json | 7 - vue-minimal/tsconfig.node.json | 26 - vue-minimal/vite.config.ts | 8 - vue-placeholder/.gitignore | 4 - vue-placeholder/README.md | 15 - vue-placeholder/index.html | 12 - vue-placeholder/package.json | 27 - vue-placeholder/src/App.vue | 7 - vue-placeholder/src/app.css | 12 - .../editor/examples/placeholder/editor.vue | 37 - .../editor/examples/placeholder/extension.ts | 12 - .../editor/examples/placeholder/index.ts | 1 - vue-placeholder/src/main.ts | 5 - vue-placeholder/tsconfig.app.json | 16 - vue-placeholder/tsconfig.json | 7 - vue-placeholder/tsconfig.node.json | 26 - vue-placeholder/vite.config.ts | 8 - vue-readonly/.gitignore | 4 - vue-readonly/README.md | 15 - vue-readonly/index.html | 12 - vue-readonly/package.json | 27 - vue-readonly/src/App.vue | 7 - vue-readonly/src/app.css | 12 - .../editor/examples/readonly/editor.vue | 36 - .../editor/examples/readonly/extension.ts | 7 - .../editor/examples/readonly/index.ts | 1 - .../editor/examples/readonly/toolbar.vue | 17 - .../editor/examples/readonly/use-readonly.ts | 18 - .../editor/sample/sample-doc-readonly.ts | 16 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - vue-readonly/src/main.ts | 5 - vue-readonly/tsconfig.app.json | 16 - vue-readonly/tsconfig.json | 7 - vue-readonly/tsconfig.node.json | 26 - vue-readonly/vite.config.ts | 8 - vue-rtl/.gitignore | 4 - vue-rtl/README.md | 15 - vue-rtl/index.html | 12 - vue-rtl/package.json | 27 - vue-rtl/src/App.vue | 7 - vue-rtl/src/app.css | 12 - .../components/editor/examples/rtl/editor.vue | 47 -- .../components/editor/examples/rtl/index.ts | 1 - .../editor/sample/sample-doc-rtl.ts | 187 ----- .../editor/sample/sample-uploader.ts | 54 -- .../editor/ui/block-handle/block-handle.vue | 39 - .../editor/ui/block-handle/index.ts | 1 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../ui/drop-indicator/drop-indicator.vue | 7 - .../editor/ui/drop-indicator/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.vue | 219 ------ .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.vue | 11 - .../editor/ui/slash-menu/slash-menu-item.vue | 24 - .../editor/ui/slash-menu/slash-menu.vue | 106 --- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.vue | 204 ------ .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-rtl/src/main.ts | 5 - vue-rtl/tsconfig.app.json | 16 - vue-rtl/tsconfig.json | 7 - vue-rtl/tsconfig.node.json | 26 - vue-rtl/vite.config.ts | 8 - vue-save-html/.gitignore | 4 - vue-save-html/README.md | 15 - vue-save-html/index.html | 12 - vue-save-html/package.json | 27 - vue-save-html/src/App.vue | 7 - vue-save-html/src/app.css | 12 - .../editor/examples/save-html/editor.vue | 75 -- .../editor/examples/save-html/index.ts | 1 - vue-save-html/src/main.ts | 5 - vue-save-html/tsconfig.app.json | 16 - vue-save-html/tsconfig.json | 7 - vue-save-html/tsconfig.node.json | 26 - vue-save-html/vite.config.ts | 8 - vue-save-json/.gitignore | 4 - vue-save-json/README.md | 15 - vue-save-json/index.html | 12 - vue-save-json/package.json | 27 - vue-save-json/src/App.vue | 7 - vue-save-json/src/app.css | 12 - .../editor/examples/save-json/editor.vue | 75 -- .../editor/examples/save-json/index.ts | 1 - vue-save-json/src/main.ts | 5 - vue-save-json/tsconfig.app.json | 16 - vue-save-json/tsconfig.json | 7 - vue-save-json/tsconfig.node.json | 26 - vue-save-json/vite.config.ts | 8 - vue-save-markdown/.gitignore | 4 - vue-save-markdown/README.md | 15 - vue-save-markdown/index.html | 12 - vue-save-markdown/package.json | 34 - vue-save-markdown/src/App.vue | 7 - vue-save-markdown/src/app.css | 12 - .../editor/examples/save-markdown/editor.vue | 79 -- .../editor/examples/save-markdown/index.ts | 1 - .../editor/examples/save-markdown/markdown.ts | 26 - vue-save-markdown/src/main.ts | 5 - vue-save-markdown/tsconfig.app.json | 16 - vue-save-markdown/tsconfig.json | 7 - vue-save-markdown/tsconfig.node.json | 26 - vue-save-markdown/vite.config.ts | 8 - vue-search/.gitignore | 4 - vue-search/README.md | 15 - vue-search/index.html | 12 - vue-search/package.json | 27 - vue-search/src/App.vue | 7 - vue-search/src/app.css | 12 - .../editor/examples/search/editor.vue | 40 - .../editor/examples/search/extension.ts | 9 - .../editor/examples/search/index.ts | 1 - .../editor/sample/sample-doc-search.ts | 79 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../src/components/editor/ui/search/index.ts | 1 - .../components/editor/ui/search/search.vue | 166 ----- vue-search/src/main.ts | 5 - vue-search/tsconfig.app.json | 16 - vue-search/tsconfig.json | 7 - vue-search/tsconfig.node.json | 26 - vue-search/vite.config.ts | 8 - vue-slash-menu/.gitignore | 4 - vue-slash-menu/README.md | 15 - vue-slash-menu/index.html | 12 - vue-slash-menu/package.json | 27 - vue-slash-menu/src/App.vue | 7 - vue-slash-menu/src/app.css | 12 - .../editor/examples/slash-menu/editor.vue | 30 - .../editor/examples/slash-menu/extension.ts | 12 - .../editor/examples/slash-menu/index.ts | 1 - .../components/editor/ui/slash-menu/index.ts | 1 - .../editor/ui/slash-menu/slash-menu-empty.vue | 11 - .../editor/ui/slash-menu/slash-menu-item.vue | 24 - .../editor/ui/slash-menu/slash-menu.vue | 106 --- vue-slash-menu/src/main.ts | 5 - vue-slash-menu/tsconfig.app.json | 16 - vue-slash-menu/tsconfig.json | 7 - vue-slash-menu/tsconfig.node.json | 26 - vue-slash-menu/vite.config.ts | 8 - vue-strike/.gitignore | 4 - vue-strike/README.md | 15 - vue-strike/index.html | 12 - vue-strike/package.json | 27 - vue-strike/src/App.vue | 7 - vue-strike/src/app.css | 12 - .../editor/examples/strike/editor.vue | 36 - .../editor/examples/strike/extension.ts | 17 - .../editor/examples/strike/index.ts | 1 - .../editor/examples/strike/toolbar.vue | 34 - .../editor/sample/sample-doc-strike.ts | 30 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - vue-strike/src/main.ts | 5 - vue-strike/tsconfig.app.json | 16 - vue-strike/tsconfig.json | 7 - vue-strike/tsconfig.node.json | 26 - vue-strike/vite.config.ts | 8 - vue-sub-sup/.gitignore | 4 - vue-sub-sup/README.md | 15 - vue-sub-sup/index.html | 12 - vue-sub-sup/package.json | 27 - vue-sub-sup/src/App.vue | 7 - vue-sub-sup/src/app.css | 12 - .../editor/examples/sub-sup/editor.vue | 36 - .../editor/examples/sub-sup/extension.ts | 32 - .../editor/examples/sub-sup/index.ts | 1 - .../editor/examples/sub-sup/toolbar.vue | 46 -- .../editor/sample/sample-doc-sub-sup.ts | 42 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - vue-sub-sup/src/main.ts | 5 - vue-sub-sup/tsconfig.app.json | 16 - vue-sub-sup/tsconfig.json | 7 - vue-sub-sup/tsconfig.node.json | 26 - vue-sub-sup/vite.config.ts | 8 - vue-table/.gitignore | 4 - vue-table/README.md | 15 - vue-table/index.html | 12 - vue-table/package.json | 27 - vue-table/src/App.vue | 7 - vue-table/src/app.css | 12 - .../editor/examples/table/editor.vue | 36 - .../editor/examples/table/extension.ts | 20 - .../components/editor/examples/table/index.ts | 1 - .../editor/sample/sample-doc-table.ts | 174 ----- .../editor/ui/table-handle/index.ts | 1 - .../editor/ui/table-handle/table-handle.vue | 204 ------ vue-table/src/main.ts | 5 - vue-table/tsconfig.app.json | 16 - vue-table/tsconfig.json | 7 - vue-table/tsconfig.node.json | 26 - vue-table/vite.config.ts | 8 - vue-text-align/.gitignore | 4 - vue-text-align/README.md | 15 - vue-text-align/index.html | 12 - vue-text-align/package.json | 27 - vue-text-align/src/App.vue | 7 - vue-text-align/src/app.css | 12 - .../editor/examples/text-align/editor.vue | 36 - .../editor/examples/text-align/extension.ts | 12 - .../editor/examples/text-align/index.ts | 1 - .../editor/examples/text-align/toolbar.vue | 80 -- .../editor/sample/sample-doc-text-align.ts | 56 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - vue-text-align/src/main.ts | 5 - vue-text-align/tsconfig.app.json | 16 - vue-text-align/tsconfig.json | 7 - vue-text-align/tsconfig.node.json | 26 - vue-text-align/vite.config.ts | 8 - vue-text-color/.gitignore | 4 - vue-text-color/README.md | 15 - vue-text-color/index.html | 12 - vue-text-color/package.json | 27 - vue-text-color/src/App.vue | 7 - vue-text-color/src/app.css | 12 - .../editor/examples/text-color/editor.vue | 36 - .../editor/examples/text-color/extension.ts | 14 - .../editor/examples/text-color/index.ts | 1 - .../examples/text-color/inline-menu.vue | 142 ---- .../editor/sample/sample-doc-text-color.ts | 120 --- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - vue-text-color/src/main.ts | 5 - vue-text-color/tsconfig.app.json | 16 - vue-text-color/tsconfig.json | 7 - vue-text-color/tsconfig.node.json | 26 - vue-text-color/vite.config.ts | 8 - vue-toolbar/.gitignore | 4 - vue-toolbar/README.md | 15 - vue-toolbar/index.html | 12 - vue-toolbar/package.json | 27 - vue-toolbar/src/App.vue | 7 - vue-toolbar/src/app.css | 12 - .../editor/examples/toolbar/editor.vue | 31 - .../editor/examples/toolbar/extension.ts | 8 - .../editor/examples/toolbar/index.ts | 1 - .../editor/sample/sample-uploader.ts | 54 -- .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-toolbar/src/main.ts | 5 - vue-toolbar/tsconfig.app.json | 16 - vue-toolbar/tsconfig.json | 7 - vue-toolbar/tsconfig.node.json | 26 - vue-toolbar/vite.config.ts | 8 - vue-tweet/.gitignore | 4 - vue-tweet/README.md | 15 - vue-tweet/index.html | 12 - vue-tweet/package.json | 28 - vue-tweet/src/App.vue | 7 - vue-tweet/src/app.css | 12 - .../editor/examples/tweet/editor.vue | 59 -- .../editor/examples/tweet/extension.ts | 43 -- .../components/editor/examples/tweet/index.ts | 1 - .../editor/examples/tweet/method-select.vue | 42 -- .../editor/examples/tweet/tweet-view.vue | 28 - .../editor/sample/sample-doc-tweet.ts | 22 - vue-tweet/src/main.ts | 5 - vue-tweet/tsconfig.app.json | 16 - vue-tweet/tsconfig.json | 7 - vue-tweet/tsconfig.node.json | 26 - vue-tweet/vite.config.ts | 8 - vue-typography/.gitignore | 4 - vue-typography/README.md | 15 - vue-typography/index.html | 12 - vue-typography/package.json | 28 - vue-typography/src/App.vue | 7 - vue-typography/src/app.css | 12 - .../editor/examples/typography/editor.vue | 38 - .../editor/examples/typography/extension.ts | 17 - .../editor/examples/typography/index.ts | 1 - .../src/components/editor/sample/katex.ts | 17 - .../editor/sample/sample-doc-typography.ts | 693 ------------------ .../editor/ui/block-handle/block-handle.vue | 39 - .../editor/ui/block-handle/index.ts | 1 - .../ui/drop-indicator/drop-indicator.vue | 7 - .../editor/ui/drop-indicator/index.ts | 1 - vue-typography/src/main.ts | 5 - vue-typography/tsconfig.app.json | 16 - vue-typography/tsconfig.json | 7 - vue-typography/tsconfig.node.json | 26 - vue-typography/vite.config.ts | 8 - vue-underline/.gitignore | 4 - vue-underline/README.md | 15 - vue-underline/index.html | 12 - vue-underline/package.json | 27 - vue-underline/src/App.vue | 7 - vue-underline/src/app.css | 12 - .../editor/examples/underline/editor.vue | 36 - .../editor/examples/underline/extension.ts | 17 - .../editor/examples/underline/index.ts | 1 - .../editor/sample/sample-doc-underline.ts | 30 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-underline/src/main.ts | 5 - vue-underline/tsconfig.app.json | 16 - vue-underline/tsconfig.json | 7 - vue-underline/tsconfig.node.json | 26 - vue-underline/vite.config.ts | 8 - vue-unmount/.gitignore | 4 - vue-unmount/README.md | 15 - vue-unmount/index.html | 12 - vue-unmount/package.json | 27 - vue-unmount/src/App.vue | 7 - vue-unmount/src/app.css | 12 - .../examples/unmount/editor-component.vue | 36 - .../editor/examples/unmount/editor.vue | 37 - .../examples/unmount/extension-component.vue | 19 - .../editor/examples/unmount/index.ts | 1 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../components/editor/ui/inline-menu/index.ts | 1 - .../editor/ui/inline-menu/inline-menu.vue | 219 ------ vue-unmount/src/main.ts | 5 - vue-unmount/tsconfig.app.json | 16 - vue-unmount/tsconfig.json | 7 - vue-unmount/tsconfig.node.json | 26 - vue-unmount/vite.config.ts | 8 - vue-user-menu-dynamic/.gitignore | 4 - vue-user-menu-dynamic/README.md | 15 - vue-user-menu-dynamic/index.html | 12 - vue-user-menu-dynamic/package.json | 27 - vue-user-menu-dynamic/src/App.vue | 7 - vue-user-menu-dynamic/src/app.css | 12 - .../examples/user-menu-dynamic/editor.vue | 29 - .../examples/user-menu-dynamic/extension.ts | 16 - .../examples/user-menu-dynamic/index.ts | 1 - .../user-menu-dynamic/use-user-query.ts | 34 - .../user-menu-dynamic/user-menu-dynamic.vue | 29 - .../editor/sample/sample-query-users.ts | 40 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.vue | 74 -- vue-user-menu-dynamic/src/main.ts | 5 - vue-user-menu-dynamic/tsconfig.app.json | 16 - vue-user-menu-dynamic/tsconfig.json | 7 - vue-user-menu-dynamic/tsconfig.node.json | 26 - vue-user-menu-dynamic/vite.config.ts | 8 - vue-user-menu/.gitignore | 4 - vue-user-menu/README.md | 15 - vue-user-menu/index.html | 12 - vue-user-menu/package.json | 27 - vue-user-menu/src/App.vue | 7 - vue-user-menu/src/app.css | 12 - .../editor/examples/user-menu/editor.vue | 34 - .../editor/examples/user-menu/extension.ts | 16 - .../editor/examples/user-menu/index.ts | 1 - .../editor/sample/sample-tag-data.ts | 12 - .../editor/sample/sample-user-data.ts | 54 -- .../components/editor/ui/tag-menu/index.ts | 1 - .../editor/ui/tag-menu/tag-menu.vue | 59 -- .../components/editor/ui/user-menu/index.ts | 1 - .../editor/ui/user-menu/user-menu.vue | 74 -- vue-user-menu/src/main.ts | 5 - vue-user-menu/tsconfig.app.json | 16 - vue-user-menu/tsconfig.json | 7 - vue-user-menu/tsconfig.node.json | 26 - vue-user-menu/vite.config.ts | 8 - vue-word-counter/.gitignore | 4 - vue-word-counter/README.md | 15 - vue-word-counter/index.html | 12 - vue-word-counter/package.json | 27 - vue-word-counter/src/App.vue | 7 - vue-word-counter/src/app.css | 12 - .../editor/examples/word-counter/editor.vue | 39 - .../editor/examples/word-counter/extension.ts | 8 - .../editor/examples/word-counter/index.ts | 1 - .../editor/sample/sample-doc-word-counter.ts | 16 - .../editor/ui/word-counter/index.ts | 1 - .../editor/ui/word-counter/word-counter.vue | 22 - vue-word-counter/src/main.ts | 5 - vue-word-counter/tsconfig.app.json | 16 - vue-word-counter/tsconfig.json | 7 - vue-word-counter/tsconfig.node.json | 26 - vue-word-counter/vite.config.ts | 8 - vue-yjs/.gitignore | 4 - vue-yjs/README.md | 15 - vue-yjs/index.html | 12 - vue-yjs/package.json | 31 - vue-yjs/src/App.vue | 7 - vue-yjs/src/app.css | 12 - .../editor/examples/yjs/editor-component.vue | 38 - .../components/editor/examples/yjs/editor.vue | 23 - .../editor/examples/yjs/extension.ts | 48 -- .../components/editor/examples/yjs/index.ts | 1 - .../components/editor/ui/button/button.vue | 42 -- .../src/components/editor/ui/button/index.ts | 1 - .../image-upload-popover.vue | 139 ---- .../editor/ui/image-upload-popover/index.ts | 1 - .../src/components/editor/ui/toolbar/index.ts | 1 - .../components/editor/ui/toolbar/toolbar.vue | 347 --------- vue-yjs/src/main.ts | 5 - vue-yjs/tsconfig.app.json | 16 - vue-yjs/tsconfig.json | 7 - vue-yjs/tsconfig.node.json | 26 - vue-yjs/vite.config.ts | 8 - 5019 files changed, 143640 deletions(-) delete mode 100644 lit-block-handle/.gitignore delete mode 100644 lit-block-handle/README.md delete mode 100644 lit-block-handle/index.html delete mode 100644 lit-block-handle/package.json delete mode 100644 lit-block-handle/src/app.css delete mode 100644 lit-block-handle/src/app.ts delete mode 100644 lit-block-handle/src/components/editor/examples/block-handle/editor.ts delete mode 100644 lit-block-handle/src/components/editor/examples/block-handle/extension.ts delete mode 100644 lit-block-handle/src/components/editor/examples/block-handle/index.ts delete mode 100644 lit-block-handle/src/components/editor/sample/sample-doc-block-handle.ts delete mode 100644 lit-block-handle/src/components/editor/ui/block-handle/block-handle.ts delete mode 100644 lit-block-handle/src/components/editor/ui/block-handle/index.ts delete mode 100644 lit-block-handle/src/components/editor/ui/code-block-view/code-block-view.ts delete mode 100644 lit-block-handle/src/components/editor/ui/code-block-view/index.ts delete mode 100644 lit-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.ts delete mode 100644 lit-block-handle/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 lit-block-handle/src/components/editor/ui/editor-context.ts delete mode 100644 lit-block-handle/src/editor.ts delete mode 100644 lit-block-handle/tsconfig.json delete mode 100644 lit-block-handle/vite.config.ts delete mode 100644 lit-code-block/.gitignore delete mode 100644 lit-code-block/README.md delete mode 100644 lit-code-block/index.html delete mode 100644 lit-code-block/package.json delete mode 100644 lit-code-block/src/app.css delete mode 100644 lit-code-block/src/app.ts delete mode 100644 lit-code-block/src/components/editor/examples/code-block/editor.ts delete mode 100644 lit-code-block/src/components/editor/examples/code-block/extension.ts delete mode 100644 lit-code-block/src/components/editor/examples/code-block/index.ts delete mode 100644 lit-code-block/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 lit-code-block/src/components/editor/sample/sample-uploader.ts delete mode 100644 lit-code-block/src/components/editor/ui/button/button.ts delete mode 100644 lit-code-block/src/components/editor/ui/button/index.ts delete mode 100644 lit-code-block/src/components/editor/ui/code-block-view/code-block-view.ts delete mode 100644 lit-code-block/src/components/editor/ui/code-block-view/index.ts delete mode 100644 lit-code-block/src/components/editor/ui/editor-context.ts delete mode 100644 lit-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.ts delete mode 100644 lit-code-block/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 lit-code-block/src/components/editor/ui/toolbar/index.ts delete mode 100644 lit-code-block/src/components/editor/ui/toolbar/toolbar.ts delete mode 100644 lit-code-block/src/editor.ts delete mode 100644 lit-code-block/tsconfig.json delete mode 100644 lit-code-block/vite.config.ts delete mode 100644 lit-minimal/.gitignore delete mode 100644 lit-minimal/README.md delete mode 100644 lit-minimal/index.html delete mode 100644 lit-minimal/package.json delete mode 100644 lit-minimal/src/app.css delete mode 100644 lit-minimal/src/app.ts delete mode 100644 lit-minimal/src/components/editor/examples/minimal/editor.ts delete mode 100644 lit-minimal/src/components/editor/examples/minimal/index.ts delete mode 100644 lit-minimal/src/editor.ts delete mode 100644 lit-minimal/tsconfig.json delete mode 100644 lit-minimal/vite.config.ts delete mode 100644 lit-slash-menu/.gitignore delete mode 100644 lit-slash-menu/README.md delete mode 100644 lit-slash-menu/index.html delete mode 100644 lit-slash-menu/package.json delete mode 100644 lit-slash-menu/src/app.css delete mode 100644 lit-slash-menu/src/app.ts delete mode 100644 lit-slash-menu/src/components/editor/examples/slash-menu/editor.ts delete mode 100644 lit-slash-menu/src/components/editor/examples/slash-menu/extension.ts delete mode 100644 lit-slash-menu/src/components/editor/examples/slash-menu/index.ts delete mode 100644 lit-slash-menu/src/components/editor/ui/editor-context.ts delete mode 100644 lit-slash-menu/src/components/editor/ui/slash-menu/index.ts delete mode 100644 lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts delete mode 100644 lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts delete mode 100644 lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts delete mode 100644 lit-slash-menu/src/editor.ts delete mode 100644 lit-slash-menu/tsconfig.json delete mode 100644 lit-slash-menu/vite.config.ts delete mode 100644 lit-table/.gitignore delete mode 100644 lit-table/README.md delete mode 100644 lit-table/index.html delete mode 100644 lit-table/package.json delete mode 100644 lit-table/src/app.css delete mode 100644 lit-table/src/app.ts delete mode 100644 lit-table/src/components/editor/examples/table/editor.ts delete mode 100644 lit-table/src/components/editor/examples/table/extension.ts delete mode 100644 lit-table/src/components/editor/examples/table/index.ts delete mode 100644 lit-table/src/components/editor/sample/sample-doc-table.ts delete mode 100644 lit-table/src/components/editor/ui/editor-context.ts delete mode 100644 lit-table/src/components/editor/ui/table-handle/index.ts delete mode 100644 lit-table/src/components/editor/ui/table-handle/table-handle.ts delete mode 100644 lit-table/src/editor.ts delete mode 100644 lit-table/tsconfig.json delete mode 100644 lit-table/vite.config.ts delete mode 100644 lit-toolbar/.gitignore delete mode 100644 lit-toolbar/README.md delete mode 100644 lit-toolbar/index.html delete mode 100644 lit-toolbar/package.json delete mode 100644 lit-toolbar/src/app.css delete mode 100644 lit-toolbar/src/app.ts delete mode 100644 lit-toolbar/src/components/editor/examples/toolbar/editor.ts delete mode 100644 lit-toolbar/src/components/editor/examples/toolbar/extension.ts delete mode 100644 lit-toolbar/src/components/editor/examples/toolbar/index.ts delete mode 100644 lit-toolbar/src/components/editor/sample/sample-uploader.ts delete mode 100644 lit-toolbar/src/components/editor/ui/button/button.ts delete mode 100644 lit-toolbar/src/components/editor/ui/button/index.ts delete mode 100644 lit-toolbar/src/components/editor/ui/editor-context.ts delete mode 100644 lit-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.ts delete mode 100644 lit-toolbar/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 lit-toolbar/src/components/editor/ui/toolbar/index.ts delete mode 100644 lit-toolbar/src/components/editor/ui/toolbar/toolbar.ts delete mode 100644 lit-toolbar/src/editor.ts delete mode 100644 lit-toolbar/tsconfig.json delete mode 100644 lit-toolbar/vite.config.ts delete mode 100644 next-full/.gitignore delete mode 100644 next-full/README.md delete mode 100644 next-full/app/app.css delete mode 100644 next-full/app/layout.tsx delete mode 100644 next-full/app/page.tsx delete mode 100644 next-full/components/editor-dynamic.tsx delete mode 100644 next-full/components/editor/examples/full/editor.tsx delete mode 100644 next-full/components/editor/examples/full/extension.ts delete mode 100644 next-full/components/editor/examples/full/html.ts delete mode 100644 next-full/components/editor/examples/full/index.ts delete mode 100644 next-full/components/editor/sample/katex.ts delete mode 100644 next-full/components/editor/sample/sample-doc-full.ts delete mode 100644 next-full/components/editor/sample/sample-tag-data.ts delete mode 100644 next-full/components/editor/sample/sample-uploader.ts delete mode 100644 next-full/components/editor/sample/sample-user-data.ts delete mode 100644 next-full/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 next-full/components/editor/ui/block-handle/index.ts delete mode 100644 next-full/components/editor/ui/button/button.tsx delete mode 100644 next-full/components/editor/ui/button/index.ts delete mode 100644 next-full/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 next-full/components/editor/ui/code-block-view/index.ts delete mode 100644 next-full/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 next-full/components/editor/ui/drop-indicator/index.ts delete mode 100644 next-full/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 next-full/components/editor/ui/image-upload-popover/index.ts delete mode 100644 next-full/components/editor/ui/image-view/image-view.tsx delete mode 100644 next-full/components/editor/ui/image-view/index.ts delete mode 100644 next-full/components/editor/ui/inline-menu/index.ts delete mode 100644 next-full/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 next-full/components/editor/ui/slash-menu/index.ts delete mode 100644 next-full/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 next-full/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 next-full/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 next-full/components/editor/ui/table-handle/index.ts delete mode 100644 next-full/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 next-full/components/editor/ui/tag-menu/index.ts delete mode 100644 next-full/components/editor/ui/tag-menu/tag-menu.tsx delete mode 100644 next-full/components/editor/ui/toolbar/index.ts delete mode 100644 next-full/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 next-full/components/editor/ui/user-menu/index.ts delete mode 100644 next-full/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 next-full/next.config.mjs delete mode 100644 next-full/package.json delete mode 100644 next-full/postcss.config.mjs delete mode 100644 next-full/tsconfig.json delete mode 100644 nuxt-full/.gitignore delete mode 100644 nuxt-full/README.md delete mode 100644 nuxt-full/nuxt.config.ts delete mode 100644 nuxt-full/package.json delete mode 100644 nuxt-full/src/app.css delete mode 100644 nuxt-full/src/app.vue delete mode 100644 nuxt-full/src/components/editor/examples/full/editor.vue delete mode 100644 nuxt-full/src/components/editor/examples/full/extension.ts delete mode 100644 nuxt-full/src/components/editor/examples/full/index.ts delete mode 100644 nuxt-full/src/components/editor/sample/katex.ts delete mode 100644 nuxt-full/src/components/editor/sample/sample-doc-full.ts delete mode 100644 nuxt-full/src/components/editor/sample/sample-tag-data.ts delete mode 100644 nuxt-full/src/components/editor/sample/sample-uploader.ts delete mode 100644 nuxt-full/src/components/editor/sample/sample-user-data.ts delete mode 100644 nuxt-full/src/components/editor/ui/block-handle/block-handle.vue delete mode 100644 nuxt-full/src/components/editor/ui/block-handle/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/button/button.vue delete mode 100644 nuxt-full/src/components/editor/ui/button/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/code-block-view/code-block-view.vue delete mode 100644 nuxt-full/src/components/editor/ui/code-block-view/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/drop-indicator/drop-indicator.vue delete mode 100644 nuxt-full/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 nuxt-full/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/image-view/image-view.vue delete mode 100644 nuxt-full/src/components/editor/ui/image-view/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/inline-menu/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/inline-menu/inline-menu.vue delete mode 100644 nuxt-full/src/components/editor/ui/slash-menu/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue delete mode 100644 nuxt-full/src/components/editor/ui/slash-menu/slash-menu-item.vue delete mode 100644 nuxt-full/src/components/editor/ui/slash-menu/slash-menu.vue delete mode 100644 nuxt-full/src/components/editor/ui/table-handle/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/table-handle/table-handle.vue delete mode 100644 nuxt-full/src/components/editor/ui/tag-menu/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/tag-menu/tag-menu.vue delete mode 100644 nuxt-full/src/components/editor/ui/toolbar/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 nuxt-full/src/components/editor/ui/user-menu/index.ts delete mode 100644 nuxt-full/src/components/editor/ui/user-menu/user-menu.vue delete mode 100644 nuxt-full/src/editor.vue delete mode 100644 nuxt-full/tsconfig.json delete mode 100644 preact-block-handle/.gitignore delete mode 100644 preact-block-handle/README.md delete mode 100644 preact-block-handle/index.html delete mode 100644 preact-block-handle/package.json delete mode 100644 preact-block-handle/src/App.tsx delete mode 100644 preact-block-handle/src/app.css delete mode 100644 preact-block-handle/src/components/editor/examples/block-handle/editor.tsx delete mode 100644 preact-block-handle/src/components/editor/examples/block-handle/extension.ts delete mode 100644 preact-block-handle/src/components/editor/examples/block-handle/index.ts delete mode 100644 preact-block-handle/src/components/editor/sample/sample-doc-block-handle.ts delete mode 100644 preact-block-handle/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 preact-block-handle/src/components/editor/ui/block-handle/index.ts delete mode 100644 preact-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 preact-block-handle/src/components/editor/ui/code-block-view/index.ts delete mode 100644 preact-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 preact-block-handle/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 preact-block-handle/src/main.tsx delete mode 100644 preact-block-handle/tsconfig.app.json delete mode 100644 preact-block-handle/tsconfig.json delete mode 100644 preact-block-handle/tsconfig.node.json delete mode 100644 preact-block-handle/vite.config.ts delete mode 100644 preact-blockquote/.gitignore delete mode 100644 preact-blockquote/README.md delete mode 100644 preact-blockquote/index.html delete mode 100644 preact-blockquote/package.json delete mode 100644 preact-blockquote/src/App.tsx delete mode 100644 preact-blockquote/src/app.css delete mode 100644 preact-blockquote/src/components/editor/examples/blockquote/editor.tsx delete mode 100644 preact-blockquote/src/components/editor/examples/blockquote/extension.ts delete mode 100644 preact-blockquote/src/components/editor/examples/blockquote/index.ts delete mode 100644 preact-blockquote/src/components/editor/ui/button/button.tsx delete mode 100644 preact-blockquote/src/components/editor/ui/button/index.ts delete mode 100644 preact-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-blockquote/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-blockquote/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-blockquote/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-blockquote/src/main.tsx delete mode 100644 preact-blockquote/tsconfig.app.json delete mode 100644 preact-blockquote/tsconfig.json delete mode 100644 preact-blockquote/tsconfig.node.json delete mode 100644 preact-blockquote/vite.config.ts delete mode 100644 preact-bold/.gitignore delete mode 100644 preact-bold/README.md delete mode 100644 preact-bold/index.html delete mode 100644 preact-bold/package.json delete mode 100644 preact-bold/src/App.tsx delete mode 100644 preact-bold/src/app.css delete mode 100644 preact-bold/src/components/editor/examples/bold/editor.tsx delete mode 100644 preact-bold/src/components/editor/examples/bold/extension.ts delete mode 100644 preact-bold/src/components/editor/examples/bold/index.ts delete mode 100644 preact-bold/src/components/editor/sample/sample-doc-bold.ts delete mode 100644 preact-bold/src/components/editor/ui/button/button.tsx delete mode 100644 preact-bold/src/components/editor/ui/button/index.ts delete mode 100644 preact-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-bold/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-bold/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-bold/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-bold/src/main.tsx delete mode 100644 preact-bold/tsconfig.app.json delete mode 100644 preact-bold/tsconfig.json delete mode 100644 preact-bold/tsconfig.node.json delete mode 100644 preact-bold/vite.config.ts delete mode 100644 preact-change-tracking/.gitignore delete mode 100644 preact-change-tracking/README.md delete mode 100644 preact-change-tracking/index.html delete mode 100644 preact-change-tracking/package.json delete mode 100644 preact-change-tracking/src/App.tsx delete mode 100644 preact-change-tracking/src/app.css delete mode 100644 preact-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx delete mode 100644 preact-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx delete mode 100644 preact-change-tracking/src/components/editor/examples/change-tracking/editor.tsx delete mode 100644 preact-change-tracking/src/components/editor/examples/change-tracking/index.ts delete mode 100644 preact-change-tracking/src/main.tsx delete mode 100644 preact-change-tracking/tsconfig.app.json delete mode 100644 preact-change-tracking/tsconfig.json delete mode 100644 preact-change-tracking/tsconfig.node.json delete mode 100644 preact-change-tracking/vite.config.ts delete mode 100644 preact-code-block-themes/.gitignore delete mode 100644 preact-code-block-themes/README.md delete mode 100644 preact-code-block-themes/index.html delete mode 100644 preact-code-block-themes/package.json delete mode 100644 preact-code-block-themes/src/App.tsx delete mode 100644 preact-code-block-themes/src/app.css delete mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx delete mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts delete mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/index.ts delete mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx delete mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx delete mode 100644 preact-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 preact-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 preact-code-block-themes/src/components/editor/ui/code-block-view/index.ts delete mode 100644 preact-code-block-themes/src/main.tsx delete mode 100644 preact-code-block-themes/tsconfig.app.json delete mode 100644 preact-code-block-themes/tsconfig.json delete mode 100644 preact-code-block-themes/tsconfig.node.json delete mode 100644 preact-code-block-themes/vite.config.ts delete mode 100644 preact-code-block/.gitignore delete mode 100644 preact-code-block/README.md delete mode 100644 preact-code-block/index.html delete mode 100644 preact-code-block/package.json delete mode 100644 preact-code-block/src/App.tsx delete mode 100644 preact-code-block/src/app.css delete mode 100644 preact-code-block/src/components/editor/examples/code-block/editor.tsx delete mode 100644 preact-code-block/src/components/editor/examples/code-block/extension.ts delete mode 100644 preact-code-block/src/components/editor/examples/code-block/index.ts delete mode 100644 preact-code-block/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 preact-code-block/src/components/editor/ui/button/button.tsx delete mode 100644 preact-code-block/src/components/editor/ui/button/index.ts delete mode 100644 preact-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 preact-code-block/src/components/editor/ui/code-block-view/index.ts delete mode 100644 preact-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-code-block/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-code-block/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-code-block/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-code-block/src/main.tsx delete mode 100644 preact-code-block/tsconfig.app.json delete mode 100644 preact-code-block/tsconfig.json delete mode 100644 preact-code-block/tsconfig.node.json delete mode 100644 preact-code-block/vite.config.ts delete mode 100644 preact-code/.gitignore delete mode 100644 preact-code/README.md delete mode 100644 preact-code/index.html delete mode 100644 preact-code/package.json delete mode 100644 preact-code/src/App.tsx delete mode 100644 preact-code/src/app.css delete mode 100644 preact-code/src/components/editor/examples/code/editor.tsx delete mode 100644 preact-code/src/components/editor/examples/code/extension.ts delete mode 100644 preact-code/src/components/editor/examples/code/index.ts delete mode 100644 preact-code/src/components/editor/sample/sample-doc-code.ts delete mode 100644 preact-code/src/components/editor/ui/button/button.tsx delete mode 100644 preact-code/src/components/editor/ui/button/index.ts delete mode 100644 preact-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-code/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-code/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-code/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-code/src/main.tsx delete mode 100644 preact-code/tsconfig.app.json delete mode 100644 preact-code/tsconfig.json delete mode 100644 preact-code/tsconfig.node.json delete mode 100644 preact-code/vite.config.ts delete mode 100644 preact-drop-cursor/.gitignore delete mode 100644 preact-drop-cursor/README.md delete mode 100644 preact-drop-cursor/index.html delete mode 100644 preact-drop-cursor/package.json delete mode 100644 preact-drop-cursor/src/App.tsx delete mode 100644 preact-drop-cursor/src/app.css delete mode 100644 preact-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx delete mode 100644 preact-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts delete mode 100644 preact-drop-cursor/src/components/editor/examples/drop-cursor/index.ts delete mode 100644 preact-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts delete mode 100644 preact-drop-cursor/src/main.tsx delete mode 100644 preact-drop-cursor/tsconfig.app.json delete mode 100644 preact-drop-cursor/tsconfig.json delete mode 100644 preact-drop-cursor/tsconfig.node.json delete mode 100644 preact-drop-cursor/vite.config.ts delete mode 100644 preact-emoji-rules/.gitignore delete mode 100644 preact-emoji-rules/README.md delete mode 100644 preact-emoji-rules/index.html delete mode 100644 preact-emoji-rules/package.json delete mode 100644 preact-emoji-rules/src/App.tsx delete mode 100644 preact-emoji-rules/src/app.css delete mode 100644 preact-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx delete mode 100644 preact-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts delete mode 100644 preact-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts delete mode 100644 preact-emoji-rules/src/components/editor/examples/emoji-rules/index.ts delete mode 100644 preact-emoji-rules/src/main.tsx delete mode 100644 preact-emoji-rules/tsconfig.app.json delete mode 100644 preact-emoji-rules/tsconfig.json delete mode 100644 preact-emoji-rules/tsconfig.node.json delete mode 100644 preact-emoji-rules/vite.config.ts delete mode 100644 preact-full/.gitignore delete mode 100644 preact-full/README.md delete mode 100644 preact-full/index.html delete mode 100644 preact-full/package.json delete mode 100644 preact-full/src/App.tsx delete mode 100644 preact-full/src/app.css delete mode 100644 preact-full/src/components/editor/examples/full/editor.tsx delete mode 100644 preact-full/src/components/editor/examples/full/extension.ts delete mode 100644 preact-full/src/components/editor/examples/full/index.ts delete mode 100644 preact-full/src/components/editor/sample/katex.ts delete mode 100644 preact-full/src/components/editor/sample/sample-doc-full.ts delete mode 100644 preact-full/src/components/editor/sample/sample-tag-data.ts delete mode 100644 preact-full/src/components/editor/sample/sample-uploader.ts delete mode 100644 preact-full/src/components/editor/sample/sample-user-data.ts delete mode 100644 preact-full/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 preact-full/src/components/editor/ui/block-handle/index.ts delete mode 100644 preact-full/src/components/editor/ui/button/button.tsx delete mode 100644 preact-full/src/components/editor/ui/button/index.ts delete mode 100644 preact-full/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 preact-full/src/components/editor/ui/code-block-view/index.ts delete mode 100644 preact-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 preact-full/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 preact-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-full/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-full/src/components/editor/ui/image-view/image-view.tsx delete mode 100644 preact-full/src/components/editor/ui/image-view/index.ts delete mode 100644 preact-full/src/components/editor/ui/inline-menu/index.ts delete mode 100644 preact-full/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 preact-full/src/components/editor/ui/slash-menu/index.ts delete mode 100644 preact-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 preact-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 preact-full/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 preact-full/src/components/editor/ui/table-handle/index.ts delete mode 100644 preact-full/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 preact-full/src/components/editor/ui/tag-menu/index.ts delete mode 100644 preact-full/src/components/editor/ui/tag-menu/tag-menu.tsx delete mode 100644 preact-full/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-full/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-full/src/components/editor/ui/user-menu/index.ts delete mode 100644 preact-full/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 preact-full/src/main.tsx delete mode 100644 preact-full/tsconfig.app.json delete mode 100644 preact-full/tsconfig.json delete mode 100644 preact-full/tsconfig.node.json delete mode 100644 preact-full/vite.config.ts delete mode 100644 preact-gap-cursor/.gitignore delete mode 100644 preact-gap-cursor/README.md delete mode 100644 preact-gap-cursor/index.html delete mode 100644 preact-gap-cursor/package.json delete mode 100644 preact-gap-cursor/src/App.tsx delete mode 100644 preact-gap-cursor/src/app.css delete mode 100644 preact-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx delete mode 100644 preact-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts delete mode 100644 preact-gap-cursor/src/components/editor/examples/gap-cursor/index.ts delete mode 100644 preact-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts delete mode 100644 preact-gap-cursor/src/main.tsx delete mode 100644 preact-gap-cursor/tsconfig.app.json delete mode 100644 preact-gap-cursor/tsconfig.json delete mode 100644 preact-gap-cursor/tsconfig.node.json delete mode 100644 preact-gap-cursor/vite.config.ts delete mode 100644 preact-hard-break/.gitignore delete mode 100644 preact-hard-break/README.md delete mode 100644 preact-hard-break/index.html delete mode 100644 preact-hard-break/package.json delete mode 100644 preact-hard-break/src/App.tsx delete mode 100644 preact-hard-break/src/app.css delete mode 100644 preact-hard-break/src/components/editor/examples/hard-break/editor.tsx delete mode 100644 preact-hard-break/src/components/editor/examples/hard-break/extension.ts delete mode 100644 preact-hard-break/src/components/editor/examples/hard-break/index.ts delete mode 100644 preact-hard-break/src/components/editor/examples/hard-break/toolbar.tsx delete mode 100644 preact-hard-break/src/components/editor/sample/sample-doc-hard-break.ts delete mode 100644 preact-hard-break/src/components/editor/ui/button/button.tsx delete mode 100644 preact-hard-break/src/components/editor/ui/button/index.ts delete mode 100644 preact-hard-break/src/main.tsx delete mode 100644 preact-hard-break/tsconfig.app.json delete mode 100644 preact-hard-break/tsconfig.json delete mode 100644 preact-hard-break/tsconfig.node.json delete mode 100644 preact-hard-break/vite.config.ts delete mode 100644 preact-heading/.gitignore delete mode 100644 preact-heading/README.md delete mode 100644 preact-heading/index.html delete mode 100644 preact-heading/package.json delete mode 100644 preact-heading/src/App.tsx delete mode 100644 preact-heading/src/app.css delete mode 100644 preact-heading/src/components/editor/examples/heading/editor.tsx delete mode 100644 preact-heading/src/components/editor/examples/heading/extension.ts delete mode 100644 preact-heading/src/components/editor/examples/heading/index.ts delete mode 100644 preact-heading/src/components/editor/sample/sample-doc-heading.ts delete mode 100644 preact-heading/src/components/editor/ui/button/button.tsx delete mode 100644 preact-heading/src/components/editor/ui/button/index.ts delete mode 100644 preact-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-heading/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-heading/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-heading/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-heading/src/main.tsx delete mode 100644 preact-heading/tsconfig.app.json delete mode 100644 preact-heading/tsconfig.json delete mode 100644 preact-heading/tsconfig.node.json delete mode 100644 preact-heading/vite.config.ts delete mode 100644 preact-highlight/.gitignore delete mode 100644 preact-highlight/README.md delete mode 100644 preact-highlight/index.html delete mode 100644 preact-highlight/package.json delete mode 100644 preact-highlight/src/App.tsx delete mode 100644 preact-highlight/src/app.css delete mode 100644 preact-highlight/src/components/editor/examples/highlight/editor.tsx delete mode 100644 preact-highlight/src/components/editor/examples/highlight/extension.ts delete mode 100644 preact-highlight/src/components/editor/examples/highlight/index.ts delete mode 100644 preact-highlight/src/components/editor/examples/highlight/toolbar.tsx delete mode 100644 preact-highlight/src/components/editor/sample/sample-doc-highlight.ts delete mode 100644 preact-highlight/src/components/editor/ui/button/button.tsx delete mode 100644 preact-highlight/src/components/editor/ui/button/index.ts delete mode 100644 preact-highlight/src/main.tsx delete mode 100644 preact-highlight/tsconfig.app.json delete mode 100644 preact-highlight/tsconfig.json delete mode 100644 preact-highlight/tsconfig.node.json delete mode 100644 preact-highlight/vite.config.ts delete mode 100644 preact-horizontal-rule/.gitignore delete mode 100644 preact-horizontal-rule/README.md delete mode 100644 preact-horizontal-rule/index.html delete mode 100644 preact-horizontal-rule/package.json delete mode 100644 preact-horizontal-rule/src/App.tsx delete mode 100644 preact-horizontal-rule/src/app.css delete mode 100644 preact-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx delete mode 100644 preact-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts delete mode 100644 preact-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts delete mode 100644 preact-horizontal-rule/src/components/editor/ui/button/button.tsx delete mode 100644 preact-horizontal-rule/src/components/editor/ui/button/index.ts delete mode 100644 preact-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-horizontal-rule/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-horizontal-rule/src/main.tsx delete mode 100644 preact-horizontal-rule/tsconfig.app.json delete mode 100644 preact-horizontal-rule/tsconfig.json delete mode 100644 preact-horizontal-rule/tsconfig.node.json delete mode 100644 preact-horizontal-rule/vite.config.ts delete mode 100644 preact-image-view/.gitignore delete mode 100644 preact-image-view/README.md delete mode 100644 preact-image-view/index.html delete mode 100644 preact-image-view/package.json delete mode 100644 preact-image-view/src/App.tsx delete mode 100644 preact-image-view/src/app.css delete mode 100644 preact-image-view/src/components/editor/examples/image-view/editor.tsx delete mode 100644 preact-image-view/src/components/editor/examples/image-view/extension.ts delete mode 100644 preact-image-view/src/components/editor/examples/image-view/index.ts delete mode 100644 preact-image-view/src/components/editor/sample/sample-doc-image.ts delete mode 100644 preact-image-view/src/components/editor/sample/sample-uploader.ts delete mode 100644 preact-image-view/src/components/editor/ui/image-view/image-view.tsx delete mode 100644 preact-image-view/src/components/editor/ui/image-view/index.ts delete mode 100644 preact-image-view/src/main.tsx delete mode 100644 preact-image-view/tsconfig.app.json delete mode 100644 preact-image-view/tsconfig.json delete mode 100644 preact-image-view/tsconfig.node.json delete mode 100644 preact-image-view/vite.config.ts delete mode 100644 preact-inline-menu/.gitignore delete mode 100644 preact-inline-menu/README.md delete mode 100644 preact-inline-menu/index.html delete mode 100644 preact-inline-menu/package.json delete mode 100644 preact-inline-menu/src/App.tsx delete mode 100644 preact-inline-menu/src/app.css delete mode 100644 preact-inline-menu/src/components/editor/examples/inline-menu/editor.tsx delete mode 100644 preact-inline-menu/src/components/editor/examples/inline-menu/extension.ts delete mode 100644 preact-inline-menu/src/components/editor/examples/inline-menu/index.ts delete mode 100644 preact-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts delete mode 100644 preact-inline-menu/src/components/editor/ui/button/button.tsx delete mode 100644 preact-inline-menu/src/components/editor/ui/button/index.ts delete mode 100644 preact-inline-menu/src/components/editor/ui/inline-menu/index.ts delete mode 100644 preact-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 preact-inline-menu/src/main.tsx delete mode 100644 preact-inline-menu/tsconfig.app.json delete mode 100644 preact-inline-menu/tsconfig.json delete mode 100644 preact-inline-menu/tsconfig.node.json delete mode 100644 preact-inline-menu/vite.config.ts delete mode 100644 preact-italic/.gitignore delete mode 100644 preact-italic/README.md delete mode 100644 preact-italic/index.html delete mode 100644 preact-italic/package.json delete mode 100644 preact-italic/src/App.tsx delete mode 100644 preact-italic/src/app.css delete mode 100644 preact-italic/src/components/editor/examples/italic/editor.tsx delete mode 100644 preact-italic/src/components/editor/examples/italic/extension.ts delete mode 100644 preact-italic/src/components/editor/examples/italic/index.ts delete mode 100644 preact-italic/src/components/editor/sample/sample-doc-italic.ts delete mode 100644 preact-italic/src/components/editor/ui/button/button.tsx delete mode 100644 preact-italic/src/components/editor/ui/button/index.ts delete mode 100644 preact-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-italic/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-italic/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-italic/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-italic/src/main.tsx delete mode 100644 preact-italic/tsconfig.app.json delete mode 100644 preact-italic/tsconfig.json delete mode 100644 preact-italic/tsconfig.node.json delete mode 100644 preact-italic/vite.config.ts delete mode 100644 preact-katex/.gitignore delete mode 100644 preact-katex/README.md delete mode 100644 preact-katex/index.html delete mode 100644 preact-katex/package.json delete mode 100644 preact-katex/src/App.tsx delete mode 100644 preact-katex/src/app.css delete mode 100644 preact-katex/src/components/editor/examples/katex/editor.tsx delete mode 100644 preact-katex/src/components/editor/examples/katex/extension.ts delete mode 100644 preact-katex/src/components/editor/examples/katex/index.ts delete mode 100644 preact-katex/src/components/editor/sample/katex.ts delete mode 100644 preact-katex/src/components/editor/sample/sample-doc-tex.ts delete mode 100644 preact-katex/src/main.tsx delete mode 100644 preact-katex/tsconfig.app.json delete mode 100644 preact-katex/tsconfig.json delete mode 100644 preact-katex/tsconfig.node.json delete mode 100644 preact-katex/vite.config.ts delete mode 100644 preact-keymap/.gitignore delete mode 100644 preact-keymap/README.md delete mode 100644 preact-keymap/index.html delete mode 100644 preact-keymap/package.json delete mode 100644 preact-keymap/src/App.tsx delete mode 100644 preact-keymap/src/app.css delete mode 100644 preact-keymap/src/components/editor/examples/keymap/editor.tsx delete mode 100644 preact-keymap/src/components/editor/examples/keymap/extension.ts delete mode 100644 preact-keymap/src/components/editor/examples/keymap/index.ts delete mode 100644 preact-keymap/src/components/editor/examples/keymap/toolbar.tsx delete mode 100644 preact-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts delete mode 100644 preact-keymap/src/components/editor/ui/button/button.tsx delete mode 100644 preact-keymap/src/components/editor/ui/button/index.ts delete mode 100644 preact-keymap/src/main.tsx delete mode 100644 preact-keymap/tsconfig.app.json delete mode 100644 preact-keymap/tsconfig.json delete mode 100644 preact-keymap/tsconfig.node.json delete mode 100644 preact-keymap/vite.config.ts delete mode 100644 preact-link-mark-view/.gitignore delete mode 100644 preact-link-mark-view/README.md delete mode 100644 preact-link-mark-view/index.html delete mode 100644 preact-link-mark-view/package.json delete mode 100644 preact-link-mark-view/src/App.tsx delete mode 100644 preact-link-mark-view/src/app.css delete mode 100644 preact-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx delete mode 100644 preact-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts delete mode 100644 preact-link-mark-view/src/components/editor/examples/link-mark-view/index.ts delete mode 100644 preact-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx delete mode 100644 preact-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts delete mode 100644 preact-link-mark-view/src/main.tsx delete mode 100644 preact-link-mark-view/tsconfig.app.json delete mode 100644 preact-link-mark-view/tsconfig.json delete mode 100644 preact-link-mark-view/tsconfig.node.json delete mode 100644 preact-link-mark-view/vite.config.ts delete mode 100644 preact-link/.gitignore delete mode 100644 preact-link/README.md delete mode 100644 preact-link/index.html delete mode 100644 preact-link/package.json delete mode 100644 preact-link/src/App.tsx delete mode 100644 preact-link/src/app.css delete mode 100644 preact-link/src/components/editor/examples/link/editor.tsx delete mode 100644 preact-link/src/components/editor/examples/link/extension.ts delete mode 100644 preact-link/src/components/editor/examples/link/index.ts delete mode 100644 preact-link/src/components/editor/sample/sample-doc-link.ts delete mode 100644 preact-link/src/components/editor/ui/button/button.tsx delete mode 100644 preact-link/src/components/editor/ui/button/index.ts delete mode 100644 preact-link/src/components/editor/ui/inline-menu/index.ts delete mode 100644 preact-link/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 preact-link/src/main.tsx delete mode 100644 preact-link/tsconfig.app.json delete mode 100644 preact-link/tsconfig.json delete mode 100644 preact-link/tsconfig.node.json delete mode 100644 preact-link/vite.config.ts delete mode 100644 preact-list-custom-checkbox/.gitignore delete mode 100644 preact-list-custom-checkbox/README.md delete mode 100644 preact-list-custom-checkbox/index.html delete mode 100644 preact-list-custom-checkbox/package.json delete mode 100644 preact-list-custom-checkbox/src/App.tsx delete mode 100644 preact-list-custom-checkbox/src/app.css delete mode 100644 preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css delete mode 100644 preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx delete mode 100644 preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts delete mode 100644 preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts delete mode 100644 preact-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts delete mode 100644 preact-list-custom-checkbox/src/components/editor/ui/button/button.tsx delete mode 100644 preact-list-custom-checkbox/src/components/editor/ui/button/index.ts delete mode 100644 preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-list-custom-checkbox/src/main.tsx delete mode 100644 preact-list-custom-checkbox/tsconfig.app.json delete mode 100644 preact-list-custom-checkbox/tsconfig.json delete mode 100644 preact-list-custom-checkbox/tsconfig.node.json delete mode 100644 preact-list-custom-checkbox/vite.config.ts delete mode 100644 preact-list/.gitignore delete mode 100644 preact-list/README.md delete mode 100644 preact-list/index.html delete mode 100644 preact-list/package.json delete mode 100644 preact-list/src/App.tsx delete mode 100644 preact-list/src/app.css delete mode 100644 preact-list/src/components/editor/examples/list/editor.tsx delete mode 100644 preact-list/src/components/editor/examples/list/extension.ts delete mode 100644 preact-list/src/components/editor/examples/list/index.ts delete mode 100644 preact-list/src/components/editor/sample/sample-doc-list.ts delete mode 100644 preact-list/src/components/editor/ui/button/button.tsx delete mode 100644 preact-list/src/components/editor/ui/button/index.ts delete mode 100644 preact-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-list/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-list/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-list/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-list/src/main.tsx delete mode 100644 preact-list/tsconfig.app.json delete mode 100644 preact-list/tsconfig.json delete mode 100644 preact-list/tsconfig.node.json delete mode 100644 preact-list/vite.config.ts delete mode 100644 preact-loro/.gitignore delete mode 100644 preact-loro/README.md delete mode 100644 preact-loro/index.html delete mode 100644 preact-loro/package.json delete mode 100644 preact-loro/src/App.tsx delete mode 100644 preact-loro/src/app.css delete mode 100644 preact-loro/src/components/editor/examples/loro/editor-component.tsx delete mode 100644 preact-loro/src/components/editor/examples/loro/editor.tsx delete mode 100644 preact-loro/src/components/editor/examples/loro/extension.ts delete mode 100644 preact-loro/src/components/editor/examples/loro/index.ts delete mode 100644 preact-loro/src/components/editor/ui/button/button.tsx delete mode 100644 preact-loro/src/components/editor/ui/button/index.ts delete mode 100644 preact-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-loro/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-loro/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-loro/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-loro/src/main.tsx delete mode 100644 preact-loro/tsconfig.app.json delete mode 100644 preact-loro/tsconfig.json delete mode 100644 preact-loro/tsconfig.node.json delete mode 100644 preact-loro/vite.config.ts delete mode 100644 preact-mark-rule/.gitignore delete mode 100644 preact-mark-rule/README.md delete mode 100644 preact-mark-rule/index.html delete mode 100644 preact-mark-rule/package.json delete mode 100644 preact-mark-rule/src/App.tsx delete mode 100644 preact-mark-rule/src/app.css delete mode 100644 preact-mark-rule/src/components/editor/examples/mark-rule/editor.tsx delete mode 100644 preact-mark-rule/src/components/editor/examples/mark-rule/extension.ts delete mode 100644 preact-mark-rule/src/components/editor/examples/mark-rule/index.ts delete mode 100644 preact-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts delete mode 100644 preact-mark-rule/src/main.tsx delete mode 100644 preact-mark-rule/tsconfig.app.json delete mode 100644 preact-mark-rule/tsconfig.json delete mode 100644 preact-mark-rule/tsconfig.node.json delete mode 100644 preact-mark-rule/vite.config.ts delete mode 100644 preact-minimal/.gitignore delete mode 100644 preact-minimal/README.md delete mode 100644 preact-minimal/index.html delete mode 100644 preact-minimal/package.json delete mode 100644 preact-minimal/src/App.tsx delete mode 100644 preact-minimal/src/app.css delete mode 100644 preact-minimal/src/components/editor/examples/minimal/editor.tsx delete mode 100644 preact-minimal/src/components/editor/examples/minimal/index.ts delete mode 100644 preact-minimal/src/main.tsx delete mode 100644 preact-minimal/tsconfig.app.json delete mode 100644 preact-minimal/tsconfig.json delete mode 100644 preact-minimal/tsconfig.node.json delete mode 100644 preact-minimal/vite.config.ts delete mode 100644 preact-placeholder/.gitignore delete mode 100644 preact-placeholder/README.md delete mode 100644 preact-placeholder/index.html delete mode 100644 preact-placeholder/package.json delete mode 100644 preact-placeholder/src/App.tsx delete mode 100644 preact-placeholder/src/app.css delete mode 100644 preact-placeholder/src/components/editor/examples/placeholder/editor.tsx delete mode 100644 preact-placeholder/src/components/editor/examples/placeholder/extension.ts delete mode 100644 preact-placeholder/src/components/editor/examples/placeholder/index.ts delete mode 100644 preact-placeholder/src/main.tsx delete mode 100644 preact-placeholder/tsconfig.app.json delete mode 100644 preact-placeholder/tsconfig.json delete mode 100644 preact-placeholder/tsconfig.node.json delete mode 100644 preact-placeholder/vite.config.ts delete mode 100644 preact-readonly/.gitignore delete mode 100644 preact-readonly/README.md delete mode 100644 preact-readonly/index.html delete mode 100644 preact-readonly/package.json delete mode 100644 preact-readonly/src/App.tsx delete mode 100644 preact-readonly/src/app.css delete mode 100644 preact-readonly/src/components/editor/examples/readonly/editor.tsx delete mode 100644 preact-readonly/src/components/editor/examples/readonly/extension.ts delete mode 100644 preact-readonly/src/components/editor/examples/readonly/index.ts delete mode 100644 preact-readonly/src/components/editor/examples/readonly/toolbar.tsx delete mode 100644 preact-readonly/src/components/editor/examples/readonly/use-readonly.ts delete mode 100644 preact-readonly/src/components/editor/sample/sample-doc-readonly.ts delete mode 100644 preact-readonly/src/components/editor/ui/button/button.tsx delete mode 100644 preact-readonly/src/components/editor/ui/button/index.ts delete mode 100644 preact-readonly/src/main.tsx delete mode 100644 preact-readonly/tsconfig.app.json delete mode 100644 preact-readonly/tsconfig.json delete mode 100644 preact-readonly/tsconfig.node.json delete mode 100644 preact-readonly/vite.config.ts delete mode 100644 preact-rtl/.gitignore delete mode 100644 preact-rtl/README.md delete mode 100644 preact-rtl/index.html delete mode 100644 preact-rtl/package.json delete mode 100644 preact-rtl/src/App.tsx delete mode 100644 preact-rtl/src/app.css delete mode 100644 preact-rtl/src/components/editor/examples/rtl/editor.tsx delete mode 100644 preact-rtl/src/components/editor/examples/rtl/index.ts delete mode 100644 preact-rtl/src/components/editor/sample/sample-doc-rtl.ts delete mode 100644 preact-rtl/src/components/editor/sample/sample-uploader.ts delete mode 100644 preact-rtl/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 preact-rtl/src/components/editor/ui/block-handle/index.ts delete mode 100644 preact-rtl/src/components/editor/ui/button/button.tsx delete mode 100644 preact-rtl/src/components/editor/ui/button/index.ts delete mode 100644 preact-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 preact-rtl/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 preact-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-rtl/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-rtl/src/components/editor/ui/inline-menu/index.ts delete mode 100644 preact-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 preact-rtl/src/components/editor/ui/slash-menu/index.ts delete mode 100644 preact-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 preact-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 preact-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 preact-rtl/src/components/editor/ui/table-handle/index.ts delete mode 100644 preact-rtl/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 preact-rtl/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-rtl/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-rtl/src/main.tsx delete mode 100644 preact-rtl/tsconfig.app.json delete mode 100644 preact-rtl/tsconfig.json delete mode 100644 preact-rtl/tsconfig.node.json delete mode 100644 preact-rtl/vite.config.ts delete mode 100644 preact-save-html/.gitignore delete mode 100644 preact-save-html/README.md delete mode 100644 preact-save-html/index.html delete mode 100644 preact-save-html/package.json delete mode 100644 preact-save-html/src/App.tsx delete mode 100644 preact-save-html/src/app.css delete mode 100644 preact-save-html/src/components/editor/examples/save-html/editor.tsx delete mode 100644 preact-save-html/src/components/editor/examples/save-html/index.ts delete mode 100644 preact-save-html/src/main.tsx delete mode 100644 preact-save-html/tsconfig.app.json delete mode 100644 preact-save-html/tsconfig.json delete mode 100644 preact-save-html/tsconfig.node.json delete mode 100644 preact-save-html/vite.config.ts delete mode 100644 preact-save-json/.gitignore delete mode 100644 preact-save-json/README.md delete mode 100644 preact-save-json/index.html delete mode 100644 preact-save-json/package.json delete mode 100644 preact-save-json/src/App.tsx delete mode 100644 preact-save-json/src/app.css delete mode 100644 preact-save-json/src/components/editor/examples/save-json/editor.tsx delete mode 100644 preact-save-json/src/components/editor/examples/save-json/index.ts delete mode 100644 preact-save-json/src/main.tsx delete mode 100644 preact-save-json/tsconfig.app.json delete mode 100644 preact-save-json/tsconfig.json delete mode 100644 preact-save-json/tsconfig.node.json delete mode 100644 preact-save-json/vite.config.ts delete mode 100644 preact-save-markdown/.gitignore delete mode 100644 preact-save-markdown/README.md delete mode 100644 preact-save-markdown/index.html delete mode 100644 preact-save-markdown/package.json delete mode 100644 preact-save-markdown/src/App.tsx delete mode 100644 preact-save-markdown/src/app.css delete mode 100644 preact-save-markdown/src/components/editor/examples/save-markdown/editor.tsx delete mode 100644 preact-save-markdown/src/components/editor/examples/save-markdown/index.ts delete mode 100644 preact-save-markdown/src/components/editor/examples/save-markdown/markdown.ts delete mode 100644 preact-save-markdown/src/main.tsx delete mode 100644 preact-save-markdown/tsconfig.app.json delete mode 100644 preact-save-markdown/tsconfig.json delete mode 100644 preact-save-markdown/tsconfig.node.json delete mode 100644 preact-save-markdown/vite.config.ts delete mode 100644 preact-search/.gitignore delete mode 100644 preact-search/README.md delete mode 100644 preact-search/index.html delete mode 100644 preact-search/package.json delete mode 100644 preact-search/src/App.tsx delete mode 100644 preact-search/src/app.css delete mode 100644 preact-search/src/components/editor/examples/search/editor.tsx delete mode 100644 preact-search/src/components/editor/examples/search/extension.ts delete mode 100644 preact-search/src/components/editor/examples/search/index.ts delete mode 100644 preact-search/src/components/editor/sample/sample-doc-search.ts delete mode 100644 preact-search/src/components/editor/ui/button/button.tsx delete mode 100644 preact-search/src/components/editor/ui/button/index.ts delete mode 100644 preact-search/src/components/editor/ui/search/index.ts delete mode 100644 preact-search/src/components/editor/ui/search/search.tsx delete mode 100644 preact-search/src/main.tsx delete mode 100644 preact-search/tsconfig.app.json delete mode 100644 preact-search/tsconfig.json delete mode 100644 preact-search/tsconfig.node.json delete mode 100644 preact-search/vite.config.ts delete mode 100644 preact-slash-menu/.gitignore delete mode 100644 preact-slash-menu/README.md delete mode 100644 preact-slash-menu/index.html delete mode 100644 preact-slash-menu/package.json delete mode 100644 preact-slash-menu/src/App.tsx delete mode 100644 preact-slash-menu/src/app.css delete mode 100644 preact-slash-menu/src/components/editor/examples/slash-menu/editor.tsx delete mode 100644 preact-slash-menu/src/components/editor/examples/slash-menu/extension.ts delete mode 100644 preact-slash-menu/src/components/editor/examples/slash-menu/index.ts delete mode 100644 preact-slash-menu/src/components/editor/ui/slash-menu/index.ts delete mode 100644 preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 preact-slash-menu/src/main.tsx delete mode 100644 preact-slash-menu/tsconfig.app.json delete mode 100644 preact-slash-menu/tsconfig.json delete mode 100644 preact-slash-menu/tsconfig.node.json delete mode 100644 preact-slash-menu/vite.config.ts delete mode 100644 preact-strike/.gitignore delete mode 100644 preact-strike/README.md delete mode 100644 preact-strike/index.html delete mode 100644 preact-strike/package.json delete mode 100644 preact-strike/src/App.tsx delete mode 100644 preact-strike/src/app.css delete mode 100644 preact-strike/src/components/editor/examples/strike/editor.tsx delete mode 100644 preact-strike/src/components/editor/examples/strike/extension.ts delete mode 100644 preact-strike/src/components/editor/examples/strike/index.ts delete mode 100644 preact-strike/src/components/editor/examples/strike/toolbar.tsx delete mode 100644 preact-strike/src/components/editor/sample/sample-doc-strike.ts delete mode 100644 preact-strike/src/components/editor/ui/button/button.tsx delete mode 100644 preact-strike/src/components/editor/ui/button/index.ts delete mode 100644 preact-strike/src/main.tsx delete mode 100644 preact-strike/tsconfig.app.json delete mode 100644 preact-strike/tsconfig.json delete mode 100644 preact-strike/tsconfig.node.json delete mode 100644 preact-strike/vite.config.ts delete mode 100644 preact-sub-sup/.gitignore delete mode 100644 preact-sub-sup/README.md delete mode 100644 preact-sub-sup/index.html delete mode 100644 preact-sub-sup/package.json delete mode 100644 preact-sub-sup/src/App.tsx delete mode 100644 preact-sub-sup/src/app.css delete mode 100644 preact-sub-sup/src/components/editor/examples/sub-sup/editor.tsx delete mode 100644 preact-sub-sup/src/components/editor/examples/sub-sup/extension.ts delete mode 100644 preact-sub-sup/src/components/editor/examples/sub-sup/index.ts delete mode 100644 preact-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx delete mode 100644 preact-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts delete mode 100644 preact-sub-sup/src/components/editor/ui/button/button.tsx delete mode 100644 preact-sub-sup/src/components/editor/ui/button/index.ts delete mode 100644 preact-sub-sup/src/main.tsx delete mode 100644 preact-sub-sup/tsconfig.app.json delete mode 100644 preact-sub-sup/tsconfig.json delete mode 100644 preact-sub-sup/tsconfig.node.json delete mode 100644 preact-sub-sup/vite.config.ts delete mode 100644 preact-table/.gitignore delete mode 100644 preact-table/README.md delete mode 100644 preact-table/index.html delete mode 100644 preact-table/package.json delete mode 100644 preact-table/src/App.tsx delete mode 100644 preact-table/src/app.css delete mode 100644 preact-table/src/components/editor/examples/table/editor.tsx delete mode 100644 preact-table/src/components/editor/examples/table/extension.ts delete mode 100644 preact-table/src/components/editor/examples/table/index.ts delete mode 100644 preact-table/src/components/editor/sample/sample-doc-table.ts delete mode 100644 preact-table/src/components/editor/ui/table-handle/index.ts delete mode 100644 preact-table/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 preact-table/src/main.tsx delete mode 100644 preact-table/tsconfig.app.json delete mode 100644 preact-table/tsconfig.json delete mode 100644 preact-table/tsconfig.node.json delete mode 100644 preact-table/vite.config.ts delete mode 100644 preact-temml/.gitignore delete mode 100644 preact-temml/README.md delete mode 100644 preact-temml/index.html delete mode 100644 preact-temml/package.json delete mode 100644 preact-temml/src/App.tsx delete mode 100644 preact-temml/src/app.css delete mode 100644 preact-temml/src/components/editor/examples/temml/editor.tsx delete mode 100644 preact-temml/src/components/editor/examples/temml/extension.ts delete mode 100644 preact-temml/src/components/editor/examples/temml/index.ts delete mode 100644 preact-temml/src/components/editor/sample/sample-doc-tex.ts delete mode 100644 preact-temml/src/components/editor/sample/temml.ts delete mode 100644 preact-temml/src/main.tsx delete mode 100644 preact-temml/tsconfig.app.json delete mode 100644 preact-temml/tsconfig.json delete mode 100644 preact-temml/tsconfig.node.json delete mode 100644 preact-temml/vite.config.ts delete mode 100644 preact-text-align/.gitignore delete mode 100644 preact-text-align/README.md delete mode 100644 preact-text-align/index.html delete mode 100644 preact-text-align/package.json delete mode 100644 preact-text-align/src/App.tsx delete mode 100644 preact-text-align/src/app.css delete mode 100644 preact-text-align/src/components/editor/examples/text-align/editor.tsx delete mode 100644 preact-text-align/src/components/editor/examples/text-align/extension.ts delete mode 100644 preact-text-align/src/components/editor/examples/text-align/index.ts delete mode 100644 preact-text-align/src/components/editor/examples/text-align/toolbar.tsx delete mode 100644 preact-text-align/src/components/editor/sample/sample-doc-text-align.ts delete mode 100644 preact-text-align/src/components/editor/ui/button/button.tsx delete mode 100644 preact-text-align/src/components/editor/ui/button/index.ts delete mode 100644 preact-text-align/src/main.tsx delete mode 100644 preact-text-align/tsconfig.app.json delete mode 100644 preact-text-align/tsconfig.json delete mode 100644 preact-text-align/tsconfig.node.json delete mode 100644 preact-text-align/vite.config.ts delete mode 100644 preact-text-color/.gitignore delete mode 100644 preact-text-color/README.md delete mode 100644 preact-text-color/index.html delete mode 100644 preact-text-color/package.json delete mode 100644 preact-text-color/src/App.tsx delete mode 100644 preact-text-color/src/app.css delete mode 100644 preact-text-color/src/components/editor/examples/text-color/editor.tsx delete mode 100644 preact-text-color/src/components/editor/examples/text-color/extension.ts delete mode 100644 preact-text-color/src/components/editor/examples/text-color/index.ts delete mode 100644 preact-text-color/src/components/editor/examples/text-color/inline-menu.tsx delete mode 100644 preact-text-color/src/components/editor/sample/sample-doc-text-color.ts delete mode 100644 preact-text-color/src/components/editor/ui/button/button.tsx delete mode 100644 preact-text-color/src/components/editor/ui/button/index.ts delete mode 100644 preact-text-color/src/main.tsx delete mode 100644 preact-text-color/tsconfig.app.json delete mode 100644 preact-text-color/tsconfig.json delete mode 100644 preact-text-color/tsconfig.node.json delete mode 100644 preact-text-color/vite.config.ts delete mode 100644 preact-toolbar/.gitignore delete mode 100644 preact-toolbar/README.md delete mode 100644 preact-toolbar/index.html delete mode 100644 preact-toolbar/package.json delete mode 100644 preact-toolbar/src/App.tsx delete mode 100644 preact-toolbar/src/app.css delete mode 100644 preact-toolbar/src/components/editor/examples/toolbar/editor.tsx delete mode 100644 preact-toolbar/src/components/editor/examples/toolbar/extension.ts delete mode 100644 preact-toolbar/src/components/editor/examples/toolbar/index.ts delete mode 100644 preact-toolbar/src/components/editor/sample/sample-uploader.ts delete mode 100644 preact-toolbar/src/components/editor/ui/button/button.tsx delete mode 100644 preact-toolbar/src/components/editor/ui/button/index.ts delete mode 100644 preact-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-toolbar/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-toolbar/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-toolbar/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-toolbar/src/main.tsx delete mode 100644 preact-toolbar/tsconfig.app.json delete mode 100644 preact-toolbar/tsconfig.json delete mode 100644 preact-toolbar/tsconfig.node.json delete mode 100644 preact-toolbar/vite.config.ts delete mode 100644 preact-typography/.gitignore delete mode 100644 preact-typography/README.md delete mode 100644 preact-typography/index.html delete mode 100644 preact-typography/package.json delete mode 100644 preact-typography/src/App.tsx delete mode 100644 preact-typography/src/app.css delete mode 100644 preact-typography/src/components/editor/examples/typography/editor.tsx delete mode 100644 preact-typography/src/components/editor/examples/typography/extension.ts delete mode 100644 preact-typography/src/components/editor/examples/typography/index.ts delete mode 100644 preact-typography/src/components/editor/sample/katex.ts delete mode 100644 preact-typography/src/components/editor/sample/sample-doc-typography.ts delete mode 100644 preact-typography/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 preact-typography/src/components/editor/ui/block-handle/index.ts delete mode 100644 preact-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 preact-typography/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 preact-typography/src/main.tsx delete mode 100644 preact-typography/tsconfig.app.json delete mode 100644 preact-typography/tsconfig.json delete mode 100644 preact-typography/tsconfig.node.json delete mode 100644 preact-typography/vite.config.ts delete mode 100644 preact-underline/.gitignore delete mode 100644 preact-underline/README.md delete mode 100644 preact-underline/index.html delete mode 100644 preact-underline/package.json delete mode 100644 preact-underline/src/App.tsx delete mode 100644 preact-underline/src/app.css delete mode 100644 preact-underline/src/components/editor/examples/underline/editor.tsx delete mode 100644 preact-underline/src/components/editor/examples/underline/extension.ts delete mode 100644 preact-underline/src/components/editor/examples/underline/index.ts delete mode 100644 preact-underline/src/components/editor/sample/sample-doc-underline.ts delete mode 100644 preact-underline/src/components/editor/ui/button/button.tsx delete mode 100644 preact-underline/src/components/editor/ui/button/index.ts delete mode 100644 preact-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-underline/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-underline/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-underline/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-underline/src/main.tsx delete mode 100644 preact-underline/tsconfig.app.json delete mode 100644 preact-underline/tsconfig.json delete mode 100644 preact-underline/tsconfig.node.json delete mode 100644 preact-underline/vite.config.ts delete mode 100644 preact-unmount/.gitignore delete mode 100644 preact-unmount/README.md delete mode 100644 preact-unmount/index.html delete mode 100644 preact-unmount/package.json delete mode 100644 preact-unmount/src/App.tsx delete mode 100644 preact-unmount/src/app.css delete mode 100644 preact-unmount/src/components/editor/examples/unmount/editor-component.tsx delete mode 100644 preact-unmount/src/components/editor/examples/unmount/editor.tsx delete mode 100644 preact-unmount/src/components/editor/examples/unmount/extension-component.tsx delete mode 100644 preact-unmount/src/components/editor/examples/unmount/index.ts delete mode 100644 preact-unmount/src/components/editor/ui/button/button.tsx delete mode 100644 preact-unmount/src/components/editor/ui/button/index.ts delete mode 100644 preact-unmount/src/components/editor/ui/inline-menu/index.ts delete mode 100644 preact-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 preact-unmount/src/main.tsx delete mode 100644 preact-unmount/tsconfig.app.json delete mode 100644 preact-unmount/tsconfig.json delete mode 100644 preact-unmount/tsconfig.node.json delete mode 100644 preact-unmount/vite.config.ts delete mode 100644 preact-user-menu-dynamic/.gitignore delete mode 100644 preact-user-menu-dynamic/README.md delete mode 100644 preact-user-menu-dynamic/index.html delete mode 100644 preact-user-menu-dynamic/package.json delete mode 100644 preact-user-menu-dynamic/src/App.tsx delete mode 100644 preact-user-menu-dynamic/src/app.css delete mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx delete mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts delete mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts delete mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts delete mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx delete mode 100644 preact-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts delete mode 100644 preact-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts delete mode 100644 preact-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts delete mode 100644 preact-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 preact-user-menu-dynamic/src/main.tsx delete mode 100644 preact-user-menu-dynamic/tsconfig.app.json delete mode 100644 preact-user-menu-dynamic/tsconfig.json delete mode 100644 preact-user-menu-dynamic/tsconfig.node.json delete mode 100644 preact-user-menu-dynamic/vite.config.ts delete mode 100644 preact-user-menu/.gitignore delete mode 100644 preact-user-menu/README.md delete mode 100644 preact-user-menu/index.html delete mode 100644 preact-user-menu/package.json delete mode 100644 preact-user-menu/src/App.tsx delete mode 100644 preact-user-menu/src/app.css delete mode 100644 preact-user-menu/src/components/editor/examples/user-menu/editor.tsx delete mode 100644 preact-user-menu/src/components/editor/examples/user-menu/extension.ts delete mode 100644 preact-user-menu/src/components/editor/examples/user-menu/index.ts delete mode 100644 preact-user-menu/src/components/editor/sample/sample-tag-data.ts delete mode 100644 preact-user-menu/src/components/editor/sample/sample-user-data.ts delete mode 100644 preact-user-menu/src/components/editor/ui/tag-menu/index.ts delete mode 100644 preact-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx delete mode 100644 preact-user-menu/src/components/editor/ui/user-menu/index.ts delete mode 100644 preact-user-menu/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 preact-user-menu/src/main.tsx delete mode 100644 preact-user-menu/tsconfig.app.json delete mode 100644 preact-user-menu/tsconfig.json delete mode 100644 preact-user-menu/tsconfig.node.json delete mode 100644 preact-user-menu/vite.config.ts delete mode 100644 preact-word-counter/.gitignore delete mode 100644 preact-word-counter/README.md delete mode 100644 preact-word-counter/index.html delete mode 100644 preact-word-counter/package.json delete mode 100644 preact-word-counter/src/App.tsx delete mode 100644 preact-word-counter/src/app.css delete mode 100644 preact-word-counter/src/components/editor/examples/word-counter/editor.tsx delete mode 100644 preact-word-counter/src/components/editor/examples/word-counter/extension.ts delete mode 100644 preact-word-counter/src/components/editor/examples/word-counter/index.ts delete mode 100644 preact-word-counter/src/components/editor/sample/sample-doc-word-counter.ts delete mode 100644 preact-word-counter/src/components/editor/ui/word-counter/index.ts delete mode 100644 preact-word-counter/src/components/editor/ui/word-counter/word-counter.tsx delete mode 100644 preact-word-counter/src/main.tsx delete mode 100644 preact-word-counter/tsconfig.app.json delete mode 100644 preact-word-counter/tsconfig.json delete mode 100644 preact-word-counter/tsconfig.node.json delete mode 100644 preact-word-counter/vite.config.ts delete mode 100644 preact-yjs/.gitignore delete mode 100644 preact-yjs/README.md delete mode 100644 preact-yjs/index.html delete mode 100644 preact-yjs/package.json delete mode 100644 preact-yjs/src/App.tsx delete mode 100644 preact-yjs/src/app.css delete mode 100644 preact-yjs/src/components/editor/examples/yjs/editor-component.tsx delete mode 100644 preact-yjs/src/components/editor/examples/yjs/editor.tsx delete mode 100644 preact-yjs/src/components/editor/examples/yjs/extension.ts delete mode 100644 preact-yjs/src/components/editor/examples/yjs/index.ts delete mode 100644 preact-yjs/src/components/editor/ui/button/button.tsx delete mode 100644 preact-yjs/src/components/editor/ui/button/index.ts delete mode 100644 preact-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 preact-yjs/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 preact-yjs/src/components/editor/ui/toolbar/index.ts delete mode 100644 preact-yjs/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 preact-yjs/src/main.tsx delete mode 100644 preact-yjs/tsconfig.app.json delete mode 100644 preact-yjs/tsconfig.json delete mode 100644 preact-yjs/tsconfig.node.json delete mode 100644 preact-yjs/vite.config.ts delete mode 100644 react-block-handle/.gitignore delete mode 100644 react-block-handle/README.md delete mode 100644 react-block-handle/index.html delete mode 100644 react-block-handle/package.json delete mode 100644 react-block-handle/src/App.tsx delete mode 100644 react-block-handle/src/app.css delete mode 100644 react-block-handle/src/components/editor/examples/block-handle/editor.tsx delete mode 100644 react-block-handle/src/components/editor/examples/block-handle/extension.ts delete mode 100644 react-block-handle/src/components/editor/examples/block-handle/index.ts delete mode 100644 react-block-handle/src/components/editor/sample/sample-doc-block-handle.ts delete mode 100644 react-block-handle/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 react-block-handle/src/components/editor/ui/block-handle/index.ts delete mode 100644 react-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 react-block-handle/src/components/editor/ui/code-block-view/index.ts delete mode 100644 react-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 react-block-handle/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 react-block-handle/src/main.tsx delete mode 100644 react-block-handle/tsconfig.app.json delete mode 100644 react-block-handle/tsconfig.json delete mode 100644 react-block-handle/tsconfig.node.json delete mode 100644 react-block-handle/vite.config.ts delete mode 100644 react-blockquote/.gitignore delete mode 100644 react-blockquote/README.md delete mode 100644 react-blockquote/index.html delete mode 100644 react-blockquote/package.json delete mode 100644 react-blockquote/src/App.tsx delete mode 100644 react-blockquote/src/app.css delete mode 100644 react-blockquote/src/components/editor/examples/blockquote/editor.tsx delete mode 100644 react-blockquote/src/components/editor/examples/blockquote/extension.ts delete mode 100644 react-blockquote/src/components/editor/examples/blockquote/index.ts delete mode 100644 react-blockquote/src/components/editor/ui/button/button.tsx delete mode 100644 react-blockquote/src/components/editor/ui/button/index.ts delete mode 100644 react-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-blockquote/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-blockquote/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-blockquote/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-blockquote/src/main.tsx delete mode 100644 react-blockquote/tsconfig.app.json delete mode 100644 react-blockquote/tsconfig.json delete mode 100644 react-blockquote/tsconfig.node.json delete mode 100644 react-blockquote/vite.config.ts delete mode 100644 react-bold/.gitignore delete mode 100644 react-bold/README.md delete mode 100644 react-bold/index.html delete mode 100644 react-bold/package.json delete mode 100644 react-bold/src/App.tsx delete mode 100644 react-bold/src/app.css delete mode 100644 react-bold/src/components/editor/examples/bold/editor.tsx delete mode 100644 react-bold/src/components/editor/examples/bold/extension.ts delete mode 100644 react-bold/src/components/editor/examples/bold/index.ts delete mode 100644 react-bold/src/components/editor/sample/sample-doc-bold.ts delete mode 100644 react-bold/src/components/editor/ui/button/button.tsx delete mode 100644 react-bold/src/components/editor/ui/button/index.ts delete mode 100644 react-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-bold/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-bold/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-bold/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-bold/src/main.tsx delete mode 100644 react-bold/tsconfig.app.json delete mode 100644 react-bold/tsconfig.json delete mode 100644 react-bold/tsconfig.node.json delete mode 100644 react-bold/vite.config.ts delete mode 100644 react-change-tracking/.gitignore delete mode 100644 react-change-tracking/README.md delete mode 100644 react-change-tracking/index.html delete mode 100644 react-change-tracking/package.json delete mode 100644 react-change-tracking/src/App.tsx delete mode 100644 react-change-tracking/src/app.css delete mode 100644 react-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx delete mode 100644 react-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx delete mode 100644 react-change-tracking/src/components/editor/examples/change-tracking/editor.tsx delete mode 100644 react-change-tracking/src/components/editor/examples/change-tracking/index.ts delete mode 100644 react-change-tracking/src/main.tsx delete mode 100644 react-change-tracking/tsconfig.app.json delete mode 100644 react-change-tracking/tsconfig.json delete mode 100644 react-change-tracking/tsconfig.node.json delete mode 100644 react-change-tracking/vite.config.ts delete mode 100644 react-code-block-themes/.gitignore delete mode 100644 react-code-block-themes/README.md delete mode 100644 react-code-block-themes/index.html delete mode 100644 react-code-block-themes/package.json delete mode 100644 react-code-block-themes/src/App.tsx delete mode 100644 react-code-block-themes/src/app.css delete mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx delete mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts delete mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/index.ts delete mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx delete mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx delete mode 100644 react-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 react-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 react-code-block-themes/src/components/editor/ui/code-block-view/index.ts delete mode 100644 react-code-block-themes/src/main.tsx delete mode 100644 react-code-block-themes/tsconfig.app.json delete mode 100644 react-code-block-themes/tsconfig.json delete mode 100644 react-code-block-themes/tsconfig.node.json delete mode 100644 react-code-block-themes/vite.config.ts delete mode 100644 react-code-block/.gitignore delete mode 100644 react-code-block/README.md delete mode 100644 react-code-block/index.html delete mode 100644 react-code-block/package.json delete mode 100644 react-code-block/src/App.tsx delete mode 100644 react-code-block/src/app.css delete mode 100644 react-code-block/src/components/editor/examples/code-block/editor.tsx delete mode 100644 react-code-block/src/components/editor/examples/code-block/extension.ts delete mode 100644 react-code-block/src/components/editor/examples/code-block/index.ts delete mode 100644 react-code-block/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 react-code-block/src/components/editor/ui/button/button.tsx delete mode 100644 react-code-block/src/components/editor/ui/button/index.ts delete mode 100644 react-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 react-code-block/src/components/editor/ui/code-block-view/index.ts delete mode 100644 react-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-code-block/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-code-block/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-code-block/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-code-block/src/main.tsx delete mode 100644 react-code-block/tsconfig.app.json delete mode 100644 react-code-block/tsconfig.json delete mode 100644 react-code-block/tsconfig.node.json delete mode 100644 react-code-block/vite.config.ts delete mode 100644 react-code/.gitignore delete mode 100644 react-code/README.md delete mode 100644 react-code/index.html delete mode 100644 react-code/package.json delete mode 100644 react-code/src/App.tsx delete mode 100644 react-code/src/app.css delete mode 100644 react-code/src/components/editor/examples/code/editor.tsx delete mode 100644 react-code/src/components/editor/examples/code/extension.ts delete mode 100644 react-code/src/components/editor/examples/code/index.ts delete mode 100644 react-code/src/components/editor/sample/sample-doc-code.ts delete mode 100644 react-code/src/components/editor/ui/button/button.tsx delete mode 100644 react-code/src/components/editor/ui/button/index.ts delete mode 100644 react-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-code/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-code/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-code/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-code/src/main.tsx delete mode 100644 react-code/tsconfig.app.json delete mode 100644 react-code/tsconfig.json delete mode 100644 react-code/tsconfig.node.json delete mode 100644 react-code/vite.config.ts delete mode 100644 react-drop-cursor/.gitignore delete mode 100644 react-drop-cursor/README.md delete mode 100644 react-drop-cursor/index.html delete mode 100644 react-drop-cursor/package.json delete mode 100644 react-drop-cursor/src/App.tsx delete mode 100644 react-drop-cursor/src/app.css delete mode 100644 react-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx delete mode 100644 react-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts delete mode 100644 react-drop-cursor/src/components/editor/examples/drop-cursor/index.ts delete mode 100644 react-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts delete mode 100644 react-drop-cursor/src/main.tsx delete mode 100644 react-drop-cursor/tsconfig.app.json delete mode 100644 react-drop-cursor/tsconfig.json delete mode 100644 react-drop-cursor/tsconfig.node.json delete mode 100644 react-drop-cursor/vite.config.ts delete mode 100644 react-emoji-rules/.gitignore delete mode 100644 react-emoji-rules/README.md delete mode 100644 react-emoji-rules/index.html delete mode 100644 react-emoji-rules/package.json delete mode 100644 react-emoji-rules/src/App.tsx delete mode 100644 react-emoji-rules/src/app.css delete mode 100644 react-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx delete mode 100644 react-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts delete mode 100644 react-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts delete mode 100644 react-emoji-rules/src/components/editor/examples/emoji-rules/index.ts delete mode 100644 react-emoji-rules/src/main.tsx delete mode 100644 react-emoji-rules/tsconfig.app.json delete mode 100644 react-emoji-rules/tsconfig.json delete mode 100644 react-emoji-rules/tsconfig.node.json delete mode 100644 react-emoji-rules/vite.config.ts delete mode 100644 react-full/.gitignore delete mode 100644 react-full/README.md delete mode 100644 react-full/index.html delete mode 100644 react-full/package.json delete mode 100644 react-full/src/App.tsx delete mode 100644 react-full/src/app.css delete mode 100644 react-full/src/components/editor/examples/full/editor.tsx delete mode 100644 react-full/src/components/editor/examples/full/extension.ts delete mode 100644 react-full/src/components/editor/examples/full/html.ts delete mode 100644 react-full/src/components/editor/examples/full/index.ts delete mode 100644 react-full/src/components/editor/sample/katex.ts delete mode 100644 react-full/src/components/editor/sample/sample-doc-full.ts delete mode 100644 react-full/src/components/editor/sample/sample-tag-data.ts delete mode 100644 react-full/src/components/editor/sample/sample-uploader.ts delete mode 100644 react-full/src/components/editor/sample/sample-user-data.ts delete mode 100644 react-full/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 react-full/src/components/editor/ui/block-handle/index.ts delete mode 100644 react-full/src/components/editor/ui/button/button.tsx delete mode 100644 react-full/src/components/editor/ui/button/index.ts delete mode 100644 react-full/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 react-full/src/components/editor/ui/code-block-view/index.ts delete mode 100644 react-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 react-full/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 react-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-full/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-full/src/components/editor/ui/image-view/image-view.tsx delete mode 100644 react-full/src/components/editor/ui/image-view/index.ts delete mode 100644 react-full/src/components/editor/ui/inline-menu/index.ts delete mode 100644 react-full/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 react-full/src/components/editor/ui/slash-menu/index.ts delete mode 100644 react-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 react-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 react-full/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 react-full/src/components/editor/ui/table-handle/index.ts delete mode 100644 react-full/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 react-full/src/components/editor/ui/tag-menu/index.ts delete mode 100644 react-full/src/components/editor/ui/tag-menu/tag-menu.tsx delete mode 100644 react-full/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-full/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-full/src/components/editor/ui/user-menu/index.ts delete mode 100644 react-full/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 react-full/src/main.tsx delete mode 100644 react-full/tsconfig.app.json delete mode 100644 react-full/tsconfig.json delete mode 100644 react-full/tsconfig.node.json delete mode 100644 react-full/vite.config.ts delete mode 100644 react-gap-cursor/.gitignore delete mode 100644 react-gap-cursor/README.md delete mode 100644 react-gap-cursor/index.html delete mode 100644 react-gap-cursor/package.json delete mode 100644 react-gap-cursor/src/App.tsx delete mode 100644 react-gap-cursor/src/app.css delete mode 100644 react-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx delete mode 100644 react-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts delete mode 100644 react-gap-cursor/src/components/editor/examples/gap-cursor/index.ts delete mode 100644 react-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts delete mode 100644 react-gap-cursor/src/main.tsx delete mode 100644 react-gap-cursor/tsconfig.app.json delete mode 100644 react-gap-cursor/tsconfig.json delete mode 100644 react-gap-cursor/tsconfig.node.json delete mode 100644 react-gap-cursor/vite.config.ts delete mode 100644 react-hard-break/.gitignore delete mode 100644 react-hard-break/README.md delete mode 100644 react-hard-break/index.html delete mode 100644 react-hard-break/package.json delete mode 100644 react-hard-break/src/App.tsx delete mode 100644 react-hard-break/src/app.css delete mode 100644 react-hard-break/src/components/editor/examples/hard-break/editor.tsx delete mode 100644 react-hard-break/src/components/editor/examples/hard-break/extension.ts delete mode 100644 react-hard-break/src/components/editor/examples/hard-break/index.ts delete mode 100644 react-hard-break/src/components/editor/examples/hard-break/toolbar.tsx delete mode 100644 react-hard-break/src/components/editor/sample/sample-doc-hard-break.ts delete mode 100644 react-hard-break/src/components/editor/ui/button/button.tsx delete mode 100644 react-hard-break/src/components/editor/ui/button/index.ts delete mode 100644 react-hard-break/src/main.tsx delete mode 100644 react-hard-break/tsconfig.app.json delete mode 100644 react-hard-break/tsconfig.json delete mode 100644 react-hard-break/tsconfig.node.json delete mode 100644 react-hard-break/vite.config.ts delete mode 100644 react-heading/.gitignore delete mode 100644 react-heading/README.md delete mode 100644 react-heading/index.html delete mode 100644 react-heading/package.json delete mode 100644 react-heading/src/App.tsx delete mode 100644 react-heading/src/app.css delete mode 100644 react-heading/src/components/editor/examples/heading/editor.tsx delete mode 100644 react-heading/src/components/editor/examples/heading/extension.ts delete mode 100644 react-heading/src/components/editor/examples/heading/index.ts delete mode 100644 react-heading/src/components/editor/sample/sample-doc-heading.ts delete mode 100644 react-heading/src/components/editor/ui/button/button.tsx delete mode 100644 react-heading/src/components/editor/ui/button/index.ts delete mode 100644 react-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-heading/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-heading/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-heading/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-heading/src/main.tsx delete mode 100644 react-heading/tsconfig.app.json delete mode 100644 react-heading/tsconfig.json delete mode 100644 react-heading/tsconfig.node.json delete mode 100644 react-heading/vite.config.ts delete mode 100644 react-highlight/.gitignore delete mode 100644 react-highlight/README.md delete mode 100644 react-highlight/index.html delete mode 100644 react-highlight/package.json delete mode 100644 react-highlight/src/App.tsx delete mode 100644 react-highlight/src/app.css delete mode 100644 react-highlight/src/components/editor/examples/highlight/editor.tsx delete mode 100644 react-highlight/src/components/editor/examples/highlight/extension.ts delete mode 100644 react-highlight/src/components/editor/examples/highlight/index.ts delete mode 100644 react-highlight/src/components/editor/examples/highlight/toolbar.tsx delete mode 100644 react-highlight/src/components/editor/sample/sample-doc-highlight.ts delete mode 100644 react-highlight/src/components/editor/ui/button/button.tsx delete mode 100644 react-highlight/src/components/editor/ui/button/index.ts delete mode 100644 react-highlight/src/main.tsx delete mode 100644 react-highlight/tsconfig.app.json delete mode 100644 react-highlight/tsconfig.json delete mode 100644 react-highlight/tsconfig.node.json delete mode 100644 react-highlight/vite.config.ts delete mode 100644 react-horizontal-rule/.gitignore delete mode 100644 react-horizontal-rule/README.md delete mode 100644 react-horizontal-rule/index.html delete mode 100644 react-horizontal-rule/package.json delete mode 100644 react-horizontal-rule/src/App.tsx delete mode 100644 react-horizontal-rule/src/app.css delete mode 100644 react-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx delete mode 100644 react-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts delete mode 100644 react-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts delete mode 100644 react-horizontal-rule/src/components/editor/ui/button/button.tsx delete mode 100644 react-horizontal-rule/src/components/editor/ui/button/index.ts delete mode 100644 react-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-horizontal-rule/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-horizontal-rule/src/main.tsx delete mode 100644 react-horizontal-rule/tsconfig.app.json delete mode 100644 react-horizontal-rule/tsconfig.json delete mode 100644 react-horizontal-rule/tsconfig.node.json delete mode 100644 react-horizontal-rule/vite.config.ts delete mode 100644 react-image-view/.gitignore delete mode 100644 react-image-view/README.md delete mode 100644 react-image-view/index.html delete mode 100644 react-image-view/package.json delete mode 100644 react-image-view/src/App.tsx delete mode 100644 react-image-view/src/app.css delete mode 100644 react-image-view/src/components/editor/examples/image-view/editor.tsx delete mode 100644 react-image-view/src/components/editor/examples/image-view/extension.ts delete mode 100644 react-image-view/src/components/editor/examples/image-view/index.ts delete mode 100644 react-image-view/src/components/editor/sample/sample-doc-image.ts delete mode 100644 react-image-view/src/components/editor/sample/sample-uploader.ts delete mode 100644 react-image-view/src/components/editor/ui/image-view/image-view.tsx delete mode 100644 react-image-view/src/components/editor/ui/image-view/index.ts delete mode 100644 react-image-view/src/main.tsx delete mode 100644 react-image-view/tsconfig.app.json delete mode 100644 react-image-view/tsconfig.json delete mode 100644 react-image-view/tsconfig.node.json delete mode 100644 react-image-view/vite.config.ts delete mode 100644 react-inline-menu/.gitignore delete mode 100644 react-inline-menu/README.md delete mode 100644 react-inline-menu/index.html delete mode 100644 react-inline-menu/package.json delete mode 100644 react-inline-menu/src/App.tsx delete mode 100644 react-inline-menu/src/app.css delete mode 100644 react-inline-menu/src/components/editor/examples/inline-menu/editor.tsx delete mode 100644 react-inline-menu/src/components/editor/examples/inline-menu/extension.ts delete mode 100644 react-inline-menu/src/components/editor/examples/inline-menu/index.ts delete mode 100644 react-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts delete mode 100644 react-inline-menu/src/components/editor/ui/button/button.tsx delete mode 100644 react-inline-menu/src/components/editor/ui/button/index.ts delete mode 100644 react-inline-menu/src/components/editor/ui/inline-menu/index.ts delete mode 100644 react-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 react-inline-menu/src/main.tsx delete mode 100644 react-inline-menu/tsconfig.app.json delete mode 100644 react-inline-menu/tsconfig.json delete mode 100644 react-inline-menu/tsconfig.node.json delete mode 100644 react-inline-menu/vite.config.ts delete mode 100644 react-italic/.gitignore delete mode 100644 react-italic/README.md delete mode 100644 react-italic/index.html delete mode 100644 react-italic/package.json delete mode 100644 react-italic/src/App.tsx delete mode 100644 react-italic/src/app.css delete mode 100644 react-italic/src/components/editor/examples/italic/editor.tsx delete mode 100644 react-italic/src/components/editor/examples/italic/extension.ts delete mode 100644 react-italic/src/components/editor/examples/italic/index.ts delete mode 100644 react-italic/src/components/editor/sample/sample-doc-italic.ts delete mode 100644 react-italic/src/components/editor/ui/button/button.tsx delete mode 100644 react-italic/src/components/editor/ui/button/index.ts delete mode 100644 react-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-italic/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-italic/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-italic/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-italic/src/main.tsx delete mode 100644 react-italic/tsconfig.app.json delete mode 100644 react-italic/tsconfig.json delete mode 100644 react-italic/tsconfig.node.json delete mode 100644 react-italic/vite.config.ts delete mode 100644 react-katex/.gitignore delete mode 100644 react-katex/README.md delete mode 100644 react-katex/index.html delete mode 100644 react-katex/package.json delete mode 100644 react-katex/src/App.tsx delete mode 100644 react-katex/src/app.css delete mode 100644 react-katex/src/components/editor/examples/katex/editor.tsx delete mode 100644 react-katex/src/components/editor/examples/katex/extension.ts delete mode 100644 react-katex/src/components/editor/examples/katex/index.ts delete mode 100644 react-katex/src/components/editor/sample/katex.ts delete mode 100644 react-katex/src/components/editor/sample/sample-doc-tex.ts delete mode 100644 react-katex/src/main.tsx delete mode 100644 react-katex/tsconfig.app.json delete mode 100644 react-katex/tsconfig.json delete mode 100644 react-katex/tsconfig.node.json delete mode 100644 react-katex/vite.config.ts delete mode 100644 react-keymap/.gitignore delete mode 100644 react-keymap/README.md delete mode 100644 react-keymap/index.html delete mode 100644 react-keymap/package.json delete mode 100644 react-keymap/src/App.tsx delete mode 100644 react-keymap/src/app.css delete mode 100644 react-keymap/src/components/editor/examples/keymap/editor.tsx delete mode 100644 react-keymap/src/components/editor/examples/keymap/extension.ts delete mode 100644 react-keymap/src/components/editor/examples/keymap/index.ts delete mode 100644 react-keymap/src/components/editor/examples/keymap/toolbar.tsx delete mode 100644 react-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts delete mode 100644 react-keymap/src/components/editor/ui/button/button.tsx delete mode 100644 react-keymap/src/components/editor/ui/button/index.ts delete mode 100644 react-keymap/src/main.tsx delete mode 100644 react-keymap/tsconfig.app.json delete mode 100644 react-keymap/tsconfig.json delete mode 100644 react-keymap/tsconfig.node.json delete mode 100644 react-keymap/vite.config.ts delete mode 100644 react-link-mark-view/.gitignore delete mode 100644 react-link-mark-view/README.md delete mode 100644 react-link-mark-view/index.html delete mode 100644 react-link-mark-view/package.json delete mode 100644 react-link-mark-view/src/App.tsx delete mode 100644 react-link-mark-view/src/app.css delete mode 100644 react-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx delete mode 100644 react-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts delete mode 100644 react-link-mark-view/src/components/editor/examples/link-mark-view/index.ts delete mode 100644 react-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx delete mode 100644 react-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts delete mode 100644 react-link-mark-view/src/main.tsx delete mode 100644 react-link-mark-view/tsconfig.app.json delete mode 100644 react-link-mark-view/tsconfig.json delete mode 100644 react-link-mark-view/tsconfig.node.json delete mode 100644 react-link-mark-view/vite.config.ts delete mode 100644 react-link/.gitignore delete mode 100644 react-link/README.md delete mode 100644 react-link/index.html delete mode 100644 react-link/package.json delete mode 100644 react-link/src/App.tsx delete mode 100644 react-link/src/app.css delete mode 100644 react-link/src/components/editor/examples/link/editor.tsx delete mode 100644 react-link/src/components/editor/examples/link/extension.ts delete mode 100644 react-link/src/components/editor/examples/link/index.ts delete mode 100644 react-link/src/components/editor/sample/sample-doc-link.ts delete mode 100644 react-link/src/components/editor/ui/button/button.tsx delete mode 100644 react-link/src/components/editor/ui/button/index.ts delete mode 100644 react-link/src/components/editor/ui/inline-menu/index.ts delete mode 100644 react-link/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 react-link/src/main.tsx delete mode 100644 react-link/tsconfig.app.json delete mode 100644 react-link/tsconfig.json delete mode 100644 react-link/tsconfig.node.json delete mode 100644 react-link/vite.config.ts delete mode 100644 react-list-custom-checkbox/.gitignore delete mode 100644 react-list-custom-checkbox/README.md delete mode 100644 react-list-custom-checkbox/index.html delete mode 100644 react-list-custom-checkbox/package.json delete mode 100644 react-list-custom-checkbox/src/App.tsx delete mode 100644 react-list-custom-checkbox/src/app.css delete mode 100644 react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css delete mode 100644 react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx delete mode 100644 react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts delete mode 100644 react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts delete mode 100644 react-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts delete mode 100644 react-list-custom-checkbox/src/components/editor/ui/button/button.tsx delete mode 100644 react-list-custom-checkbox/src/components/editor/ui/button/index.ts delete mode 100644 react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-list-custom-checkbox/src/main.tsx delete mode 100644 react-list-custom-checkbox/tsconfig.app.json delete mode 100644 react-list-custom-checkbox/tsconfig.json delete mode 100644 react-list-custom-checkbox/tsconfig.node.json delete mode 100644 react-list-custom-checkbox/vite.config.ts delete mode 100644 react-list/.gitignore delete mode 100644 react-list/README.md delete mode 100644 react-list/index.html delete mode 100644 react-list/package.json delete mode 100644 react-list/src/App.tsx delete mode 100644 react-list/src/app.css delete mode 100644 react-list/src/components/editor/examples/list/editor.tsx delete mode 100644 react-list/src/components/editor/examples/list/extension.ts delete mode 100644 react-list/src/components/editor/examples/list/index.ts delete mode 100644 react-list/src/components/editor/sample/sample-doc-list.ts delete mode 100644 react-list/src/components/editor/ui/button/button.tsx delete mode 100644 react-list/src/components/editor/ui/button/index.ts delete mode 100644 react-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-list/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-list/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-list/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-list/src/main.tsx delete mode 100644 react-list/tsconfig.app.json delete mode 100644 react-list/tsconfig.json delete mode 100644 react-list/tsconfig.node.json delete mode 100644 react-list/vite.config.ts delete mode 100644 react-loro/.gitignore delete mode 100644 react-loro/README.md delete mode 100644 react-loro/index.html delete mode 100644 react-loro/package.json delete mode 100644 react-loro/src/App.tsx delete mode 100644 react-loro/src/app.css delete mode 100644 react-loro/src/components/editor/examples/loro/editor-component.tsx delete mode 100644 react-loro/src/components/editor/examples/loro/editor.tsx delete mode 100644 react-loro/src/components/editor/examples/loro/extension.ts delete mode 100644 react-loro/src/components/editor/examples/loro/index.ts delete mode 100644 react-loro/src/components/editor/ui/button/button.tsx delete mode 100644 react-loro/src/components/editor/ui/button/index.ts delete mode 100644 react-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-loro/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-loro/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-loro/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-loro/src/main.tsx delete mode 100644 react-loro/tsconfig.app.json delete mode 100644 react-loro/tsconfig.json delete mode 100644 react-loro/tsconfig.node.json delete mode 100644 react-loro/vite.config.ts delete mode 100644 react-mark-rule/.gitignore delete mode 100644 react-mark-rule/README.md delete mode 100644 react-mark-rule/index.html delete mode 100644 react-mark-rule/package.json delete mode 100644 react-mark-rule/src/App.tsx delete mode 100644 react-mark-rule/src/app.css delete mode 100644 react-mark-rule/src/components/editor/examples/mark-rule/editor.tsx delete mode 100644 react-mark-rule/src/components/editor/examples/mark-rule/extension.ts delete mode 100644 react-mark-rule/src/components/editor/examples/mark-rule/index.ts delete mode 100644 react-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts delete mode 100644 react-mark-rule/src/main.tsx delete mode 100644 react-mark-rule/tsconfig.app.json delete mode 100644 react-mark-rule/tsconfig.json delete mode 100644 react-mark-rule/tsconfig.node.json delete mode 100644 react-mark-rule/vite.config.ts delete mode 100644 react-minimal/.gitignore delete mode 100644 react-minimal/README.md delete mode 100644 react-minimal/index.html delete mode 100644 react-minimal/package.json delete mode 100644 react-minimal/src/App.tsx delete mode 100644 react-minimal/src/app.css delete mode 100644 react-minimal/src/components/editor/examples/minimal/editor.tsx delete mode 100644 react-minimal/src/components/editor/examples/minimal/index.ts delete mode 100644 react-minimal/src/main.tsx delete mode 100644 react-minimal/tsconfig.app.json delete mode 100644 react-minimal/tsconfig.json delete mode 100644 react-minimal/tsconfig.node.json delete mode 100644 react-minimal/vite.config.ts delete mode 100644 react-page/.gitignore delete mode 100644 react-page/README.md delete mode 100644 react-page/index.html delete mode 100644 react-page/package.json delete mode 100644 react-page/src/App.tsx delete mode 100644 react-page/src/app.css delete mode 100644 react-page/src/components/editor/examples/page/editor.tsx delete mode 100644 react-page/src/components/editor/examples/page/extension.ts delete mode 100644 react-page/src/components/editor/examples/page/index.ts delete mode 100644 react-page/src/components/editor/examples/page/paper-controller.tsx delete mode 100644 react-page/src/components/editor/examples/page/zoom.css delete mode 100644 react-page/src/components/editor/sample/sample-doc-page.ts delete mode 100644 react-page/src/main.tsx delete mode 100644 react-page/tsconfig.app.json delete mode 100644 react-page/tsconfig.json delete mode 100644 react-page/tsconfig.node.json delete mode 100644 react-page/vite.config.ts delete mode 100644 react-placeholder/.gitignore delete mode 100644 react-placeholder/README.md delete mode 100644 react-placeholder/index.html delete mode 100644 react-placeholder/package.json delete mode 100644 react-placeholder/src/App.tsx delete mode 100644 react-placeholder/src/app.css delete mode 100644 react-placeholder/src/components/editor/examples/placeholder/editor.tsx delete mode 100644 react-placeholder/src/components/editor/examples/placeholder/extension.ts delete mode 100644 react-placeholder/src/components/editor/examples/placeholder/index.ts delete mode 100644 react-placeholder/src/main.tsx delete mode 100644 react-placeholder/tsconfig.app.json delete mode 100644 react-placeholder/tsconfig.json delete mode 100644 react-placeholder/tsconfig.node.json delete mode 100644 react-placeholder/vite.config.ts delete mode 100644 react-readonly/.gitignore delete mode 100644 react-readonly/README.md delete mode 100644 react-readonly/index.html delete mode 100644 react-readonly/package.json delete mode 100644 react-readonly/src/App.tsx delete mode 100644 react-readonly/src/app.css delete mode 100644 react-readonly/src/components/editor/examples/readonly/editor.tsx delete mode 100644 react-readonly/src/components/editor/examples/readonly/extension.ts delete mode 100644 react-readonly/src/components/editor/examples/readonly/index.ts delete mode 100644 react-readonly/src/components/editor/examples/readonly/toolbar.tsx delete mode 100644 react-readonly/src/components/editor/examples/readonly/use-readonly.ts delete mode 100644 react-readonly/src/components/editor/sample/sample-doc-readonly.ts delete mode 100644 react-readonly/src/components/editor/ui/button/button.tsx delete mode 100644 react-readonly/src/components/editor/ui/button/index.ts delete mode 100644 react-readonly/src/main.tsx delete mode 100644 react-readonly/tsconfig.app.json delete mode 100644 react-readonly/tsconfig.json delete mode 100644 react-readonly/tsconfig.node.json delete mode 100644 react-readonly/vite.config.ts delete mode 100644 react-rtl/.gitignore delete mode 100644 react-rtl/README.md delete mode 100644 react-rtl/index.html delete mode 100644 react-rtl/package.json delete mode 100644 react-rtl/src/App.tsx delete mode 100644 react-rtl/src/app.css delete mode 100644 react-rtl/src/components/editor/examples/rtl/editor.tsx delete mode 100644 react-rtl/src/components/editor/examples/rtl/index.ts delete mode 100644 react-rtl/src/components/editor/sample/sample-doc-rtl.ts delete mode 100644 react-rtl/src/components/editor/sample/sample-uploader.ts delete mode 100644 react-rtl/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 react-rtl/src/components/editor/ui/block-handle/index.ts delete mode 100644 react-rtl/src/components/editor/ui/button/button.tsx delete mode 100644 react-rtl/src/components/editor/ui/button/index.ts delete mode 100644 react-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 react-rtl/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 react-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-rtl/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-rtl/src/components/editor/ui/inline-menu/index.ts delete mode 100644 react-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 react-rtl/src/components/editor/ui/slash-menu/index.ts delete mode 100644 react-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 react-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 react-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 react-rtl/src/components/editor/ui/table-handle/index.ts delete mode 100644 react-rtl/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 react-rtl/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-rtl/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-rtl/src/main.tsx delete mode 100644 react-rtl/tsconfig.app.json delete mode 100644 react-rtl/tsconfig.json delete mode 100644 react-rtl/tsconfig.node.json delete mode 100644 react-rtl/vite.config.ts delete mode 100644 react-save-html/.gitignore delete mode 100644 react-save-html/README.md delete mode 100644 react-save-html/index.html delete mode 100644 react-save-html/package.json delete mode 100644 react-save-html/src/App.tsx delete mode 100644 react-save-html/src/app.css delete mode 100644 react-save-html/src/components/editor/examples/save-html/editor.tsx delete mode 100644 react-save-html/src/components/editor/examples/save-html/index.ts delete mode 100644 react-save-html/src/main.tsx delete mode 100644 react-save-html/tsconfig.app.json delete mode 100644 react-save-html/tsconfig.json delete mode 100644 react-save-html/tsconfig.node.json delete mode 100644 react-save-html/vite.config.ts delete mode 100644 react-save-json/.gitignore delete mode 100644 react-save-json/README.md delete mode 100644 react-save-json/index.html delete mode 100644 react-save-json/package.json delete mode 100644 react-save-json/src/App.tsx delete mode 100644 react-save-json/src/app.css delete mode 100644 react-save-json/src/components/editor/examples/save-json/editor.tsx delete mode 100644 react-save-json/src/components/editor/examples/save-json/index.ts delete mode 100644 react-save-json/src/main.tsx delete mode 100644 react-save-json/tsconfig.app.json delete mode 100644 react-save-json/tsconfig.json delete mode 100644 react-save-json/tsconfig.node.json delete mode 100644 react-save-json/vite.config.ts delete mode 100644 react-save-markdown/.gitignore delete mode 100644 react-save-markdown/README.md delete mode 100644 react-save-markdown/index.html delete mode 100644 react-save-markdown/package.json delete mode 100644 react-save-markdown/src/App.tsx delete mode 100644 react-save-markdown/src/app.css delete mode 100644 react-save-markdown/src/components/editor/examples/save-markdown/editor.tsx delete mode 100644 react-save-markdown/src/components/editor/examples/save-markdown/index.ts delete mode 100644 react-save-markdown/src/components/editor/examples/save-markdown/markdown.ts delete mode 100644 react-save-markdown/src/main.tsx delete mode 100644 react-save-markdown/tsconfig.app.json delete mode 100644 react-save-markdown/tsconfig.json delete mode 100644 react-save-markdown/tsconfig.node.json delete mode 100644 react-save-markdown/vite.config.ts delete mode 100644 react-search/.gitignore delete mode 100644 react-search/README.md delete mode 100644 react-search/index.html delete mode 100644 react-search/package.json delete mode 100644 react-search/src/App.tsx delete mode 100644 react-search/src/app.css delete mode 100644 react-search/src/components/editor/examples/search/editor.tsx delete mode 100644 react-search/src/components/editor/examples/search/extension.ts delete mode 100644 react-search/src/components/editor/examples/search/index.ts delete mode 100644 react-search/src/components/editor/sample/sample-doc-search.ts delete mode 100644 react-search/src/components/editor/ui/button/button.tsx delete mode 100644 react-search/src/components/editor/ui/button/index.ts delete mode 100644 react-search/src/components/editor/ui/search/index.ts delete mode 100644 react-search/src/components/editor/ui/search/search.tsx delete mode 100644 react-search/src/main.tsx delete mode 100644 react-search/tsconfig.app.json delete mode 100644 react-search/tsconfig.json delete mode 100644 react-search/tsconfig.node.json delete mode 100644 react-search/vite.config.ts delete mode 100644 react-slash-menu/.gitignore delete mode 100644 react-slash-menu/README.md delete mode 100644 react-slash-menu/index.html delete mode 100644 react-slash-menu/package.json delete mode 100644 react-slash-menu/src/App.tsx delete mode 100644 react-slash-menu/src/app.css delete mode 100644 react-slash-menu/src/components/editor/examples/slash-menu/editor.tsx delete mode 100644 react-slash-menu/src/components/editor/examples/slash-menu/extension.ts delete mode 100644 react-slash-menu/src/components/editor/examples/slash-menu/index.ts delete mode 100644 react-slash-menu/src/components/editor/ui/slash-menu/index.ts delete mode 100644 react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 react-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 react-slash-menu/src/main.tsx delete mode 100644 react-slash-menu/tsconfig.app.json delete mode 100644 react-slash-menu/tsconfig.json delete mode 100644 react-slash-menu/tsconfig.node.json delete mode 100644 react-slash-menu/vite.config.ts delete mode 100644 react-strike/.gitignore delete mode 100644 react-strike/README.md delete mode 100644 react-strike/index.html delete mode 100644 react-strike/package.json delete mode 100644 react-strike/src/App.tsx delete mode 100644 react-strike/src/app.css delete mode 100644 react-strike/src/components/editor/examples/strike/editor.tsx delete mode 100644 react-strike/src/components/editor/examples/strike/extension.ts delete mode 100644 react-strike/src/components/editor/examples/strike/index.ts delete mode 100644 react-strike/src/components/editor/examples/strike/toolbar.tsx delete mode 100644 react-strike/src/components/editor/sample/sample-doc-strike.ts delete mode 100644 react-strike/src/components/editor/ui/button/button.tsx delete mode 100644 react-strike/src/components/editor/ui/button/index.ts delete mode 100644 react-strike/src/main.tsx delete mode 100644 react-strike/tsconfig.app.json delete mode 100644 react-strike/tsconfig.json delete mode 100644 react-strike/tsconfig.node.json delete mode 100644 react-strike/vite.config.ts delete mode 100644 react-sub-sup/.gitignore delete mode 100644 react-sub-sup/README.md delete mode 100644 react-sub-sup/index.html delete mode 100644 react-sub-sup/package.json delete mode 100644 react-sub-sup/src/App.tsx delete mode 100644 react-sub-sup/src/app.css delete mode 100644 react-sub-sup/src/components/editor/examples/sub-sup/editor.tsx delete mode 100644 react-sub-sup/src/components/editor/examples/sub-sup/extension.ts delete mode 100644 react-sub-sup/src/components/editor/examples/sub-sup/index.ts delete mode 100644 react-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx delete mode 100644 react-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts delete mode 100644 react-sub-sup/src/components/editor/ui/button/button.tsx delete mode 100644 react-sub-sup/src/components/editor/ui/button/index.ts delete mode 100644 react-sub-sup/src/main.tsx delete mode 100644 react-sub-sup/tsconfig.app.json delete mode 100644 react-sub-sup/tsconfig.json delete mode 100644 react-sub-sup/tsconfig.node.json delete mode 100644 react-sub-sup/vite.config.ts delete mode 100644 react-table/.gitignore delete mode 100644 react-table/README.md delete mode 100644 react-table/index.html delete mode 100644 react-table/package.json delete mode 100644 react-table/src/App.tsx delete mode 100644 react-table/src/app.css delete mode 100644 react-table/src/components/editor/examples/table/editor.tsx delete mode 100644 react-table/src/components/editor/examples/table/extension.ts delete mode 100644 react-table/src/components/editor/examples/table/index.ts delete mode 100644 react-table/src/components/editor/sample/sample-doc-table.ts delete mode 100644 react-table/src/components/editor/ui/table-handle/index.ts delete mode 100644 react-table/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 react-table/src/main.tsx delete mode 100644 react-table/tsconfig.app.json delete mode 100644 react-table/tsconfig.json delete mode 100644 react-table/tsconfig.node.json delete mode 100644 react-table/vite.config.ts delete mode 100644 react-temml/.gitignore delete mode 100644 react-temml/README.md delete mode 100644 react-temml/index.html delete mode 100644 react-temml/package.json delete mode 100644 react-temml/src/App.tsx delete mode 100644 react-temml/src/app.css delete mode 100644 react-temml/src/components/editor/examples/temml/editor.tsx delete mode 100644 react-temml/src/components/editor/examples/temml/extension.ts delete mode 100644 react-temml/src/components/editor/examples/temml/index.ts delete mode 100644 react-temml/src/components/editor/sample/sample-doc-tex.ts delete mode 100644 react-temml/src/components/editor/sample/temml.ts delete mode 100644 react-temml/src/main.tsx delete mode 100644 react-temml/tsconfig.app.json delete mode 100644 react-temml/tsconfig.json delete mode 100644 react-temml/tsconfig.node.json delete mode 100644 react-temml/vite.config.ts delete mode 100644 react-text-align/.gitignore delete mode 100644 react-text-align/README.md delete mode 100644 react-text-align/index.html delete mode 100644 react-text-align/package.json delete mode 100644 react-text-align/src/App.tsx delete mode 100644 react-text-align/src/app.css delete mode 100644 react-text-align/src/components/editor/examples/text-align/editor.tsx delete mode 100644 react-text-align/src/components/editor/examples/text-align/extension.ts delete mode 100644 react-text-align/src/components/editor/examples/text-align/index.ts delete mode 100644 react-text-align/src/components/editor/examples/text-align/toolbar.tsx delete mode 100644 react-text-align/src/components/editor/sample/sample-doc-text-align.ts delete mode 100644 react-text-align/src/components/editor/ui/button/button.tsx delete mode 100644 react-text-align/src/components/editor/ui/button/index.ts delete mode 100644 react-text-align/src/main.tsx delete mode 100644 react-text-align/tsconfig.app.json delete mode 100644 react-text-align/tsconfig.json delete mode 100644 react-text-align/tsconfig.node.json delete mode 100644 react-text-align/vite.config.ts delete mode 100644 react-text-color/.gitignore delete mode 100644 react-text-color/README.md delete mode 100644 react-text-color/index.html delete mode 100644 react-text-color/package.json delete mode 100644 react-text-color/src/App.tsx delete mode 100644 react-text-color/src/app.css delete mode 100644 react-text-color/src/components/editor/examples/text-color/editor.tsx delete mode 100644 react-text-color/src/components/editor/examples/text-color/extension.ts delete mode 100644 react-text-color/src/components/editor/examples/text-color/index.ts delete mode 100644 react-text-color/src/components/editor/examples/text-color/inline-menu.tsx delete mode 100644 react-text-color/src/components/editor/sample/sample-doc-text-color.ts delete mode 100644 react-text-color/src/components/editor/ui/button/button.tsx delete mode 100644 react-text-color/src/components/editor/ui/button/index.ts delete mode 100644 react-text-color/src/main.tsx delete mode 100644 react-text-color/tsconfig.app.json delete mode 100644 react-text-color/tsconfig.json delete mode 100644 react-text-color/tsconfig.node.json delete mode 100644 react-text-color/vite.config.ts delete mode 100644 react-toolbar/.gitignore delete mode 100644 react-toolbar/README.md delete mode 100644 react-toolbar/index.html delete mode 100644 react-toolbar/package.json delete mode 100644 react-toolbar/src/App.tsx delete mode 100644 react-toolbar/src/app.css delete mode 100644 react-toolbar/src/components/editor/examples/toolbar/editor.tsx delete mode 100644 react-toolbar/src/components/editor/examples/toolbar/extension.ts delete mode 100644 react-toolbar/src/components/editor/examples/toolbar/index.ts delete mode 100644 react-toolbar/src/components/editor/sample/sample-uploader.ts delete mode 100644 react-toolbar/src/components/editor/ui/button/button.tsx delete mode 100644 react-toolbar/src/components/editor/ui/button/index.ts delete mode 100644 react-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-toolbar/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-toolbar/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-toolbar/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-toolbar/src/main.tsx delete mode 100644 react-toolbar/tsconfig.app.json delete mode 100644 react-toolbar/tsconfig.json delete mode 100644 react-toolbar/tsconfig.node.json delete mode 100644 react-toolbar/vite.config.ts delete mode 100644 react-tweet/.gitignore delete mode 100644 react-tweet/README.md delete mode 100644 react-tweet/index.html delete mode 100644 react-tweet/package.json delete mode 100644 react-tweet/src/App.tsx delete mode 100644 react-tweet/src/app.css delete mode 100644 react-tweet/src/components/editor/examples/tweet/editor.tsx delete mode 100644 react-tweet/src/components/editor/examples/tweet/extension.ts delete mode 100644 react-tweet/src/components/editor/examples/tweet/index.ts delete mode 100644 react-tweet/src/components/editor/examples/tweet/method-select.tsx delete mode 100644 react-tweet/src/components/editor/examples/tweet/tweet-view.tsx delete mode 100644 react-tweet/src/components/editor/sample/sample-doc-tweet.ts delete mode 100644 react-tweet/src/main.tsx delete mode 100644 react-tweet/tsconfig.app.json delete mode 100644 react-tweet/tsconfig.json delete mode 100644 react-tweet/tsconfig.node.json delete mode 100644 react-tweet/vite.config.ts delete mode 100644 react-typography/.gitignore delete mode 100644 react-typography/README.md delete mode 100644 react-typography/index.html delete mode 100644 react-typography/package.json delete mode 100644 react-typography/src/App.tsx delete mode 100644 react-typography/src/app.css delete mode 100644 react-typography/src/components/editor/examples/typography/editor.tsx delete mode 100644 react-typography/src/components/editor/examples/typography/extension.ts delete mode 100644 react-typography/src/components/editor/examples/typography/index.ts delete mode 100644 react-typography/src/components/editor/sample/katex.ts delete mode 100644 react-typography/src/components/editor/sample/sample-doc-typography.ts delete mode 100644 react-typography/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 react-typography/src/components/editor/ui/block-handle/index.ts delete mode 100644 react-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 react-typography/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 react-typography/src/main.tsx delete mode 100644 react-typography/tsconfig.app.json delete mode 100644 react-typography/tsconfig.json delete mode 100644 react-typography/tsconfig.node.json delete mode 100644 react-typography/vite.config.ts delete mode 100644 react-underline/.gitignore delete mode 100644 react-underline/README.md delete mode 100644 react-underline/index.html delete mode 100644 react-underline/package.json delete mode 100644 react-underline/src/App.tsx delete mode 100644 react-underline/src/app.css delete mode 100644 react-underline/src/components/editor/examples/underline/editor.tsx delete mode 100644 react-underline/src/components/editor/examples/underline/extension.ts delete mode 100644 react-underline/src/components/editor/examples/underline/index.ts delete mode 100644 react-underline/src/components/editor/sample/sample-doc-underline.ts delete mode 100644 react-underline/src/components/editor/ui/button/button.tsx delete mode 100644 react-underline/src/components/editor/ui/button/index.ts delete mode 100644 react-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-underline/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-underline/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-underline/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-underline/src/main.tsx delete mode 100644 react-underline/tsconfig.app.json delete mode 100644 react-underline/tsconfig.json delete mode 100644 react-underline/tsconfig.node.json delete mode 100644 react-underline/vite.config.ts delete mode 100644 react-unmount/.gitignore delete mode 100644 react-unmount/README.md delete mode 100644 react-unmount/index.html delete mode 100644 react-unmount/package.json delete mode 100644 react-unmount/src/App.tsx delete mode 100644 react-unmount/src/app.css delete mode 100644 react-unmount/src/components/editor/examples/unmount/editor-component.tsx delete mode 100644 react-unmount/src/components/editor/examples/unmount/editor.tsx delete mode 100644 react-unmount/src/components/editor/examples/unmount/extension-component.tsx delete mode 100644 react-unmount/src/components/editor/examples/unmount/index.ts delete mode 100644 react-unmount/src/components/editor/ui/button/button.tsx delete mode 100644 react-unmount/src/components/editor/ui/button/index.ts delete mode 100644 react-unmount/src/components/editor/ui/inline-menu/index.ts delete mode 100644 react-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 react-unmount/src/main.tsx delete mode 100644 react-unmount/tsconfig.app.json delete mode 100644 react-unmount/tsconfig.json delete mode 100644 react-unmount/tsconfig.node.json delete mode 100644 react-unmount/vite.config.ts delete mode 100644 react-user-menu-dynamic/.gitignore delete mode 100644 react-user-menu-dynamic/README.md delete mode 100644 react-user-menu-dynamic/index.html delete mode 100644 react-user-menu-dynamic/package.json delete mode 100644 react-user-menu-dynamic/src/App.tsx delete mode 100644 react-user-menu-dynamic/src/app.css delete mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx delete mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts delete mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts delete mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts delete mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx delete mode 100644 react-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts delete mode 100644 react-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts delete mode 100644 react-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts delete mode 100644 react-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 react-user-menu-dynamic/src/main.tsx delete mode 100644 react-user-menu-dynamic/tsconfig.app.json delete mode 100644 react-user-menu-dynamic/tsconfig.json delete mode 100644 react-user-menu-dynamic/tsconfig.node.json delete mode 100644 react-user-menu-dynamic/vite.config.ts delete mode 100644 react-user-menu/.gitignore delete mode 100644 react-user-menu/README.md delete mode 100644 react-user-menu/index.html delete mode 100644 react-user-menu/package.json delete mode 100644 react-user-menu/src/App.tsx delete mode 100644 react-user-menu/src/app.css delete mode 100644 react-user-menu/src/components/editor/examples/user-menu/editor.tsx delete mode 100644 react-user-menu/src/components/editor/examples/user-menu/extension.ts delete mode 100644 react-user-menu/src/components/editor/examples/user-menu/index.ts delete mode 100644 react-user-menu/src/components/editor/sample/sample-tag-data.ts delete mode 100644 react-user-menu/src/components/editor/sample/sample-user-data.ts delete mode 100644 react-user-menu/src/components/editor/ui/tag-menu/index.ts delete mode 100644 react-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx delete mode 100644 react-user-menu/src/components/editor/ui/user-menu/index.ts delete mode 100644 react-user-menu/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 react-user-menu/src/main.tsx delete mode 100644 react-user-menu/tsconfig.app.json delete mode 100644 react-user-menu/tsconfig.json delete mode 100644 react-user-menu/tsconfig.node.json delete mode 100644 react-user-menu/vite.config.ts delete mode 100644 react-word-counter/.gitignore delete mode 100644 react-word-counter/README.md delete mode 100644 react-word-counter/index.html delete mode 100644 react-word-counter/package.json delete mode 100644 react-word-counter/src/App.tsx delete mode 100644 react-word-counter/src/app.css delete mode 100644 react-word-counter/src/components/editor/examples/word-counter/editor.tsx delete mode 100644 react-word-counter/src/components/editor/examples/word-counter/extension.ts delete mode 100644 react-word-counter/src/components/editor/examples/word-counter/index.ts delete mode 100644 react-word-counter/src/components/editor/sample/sample-doc-word-counter.ts delete mode 100644 react-word-counter/src/components/editor/ui/word-counter/index.ts delete mode 100644 react-word-counter/src/components/editor/ui/word-counter/word-counter.tsx delete mode 100644 react-word-counter/src/main.tsx delete mode 100644 react-word-counter/tsconfig.app.json delete mode 100644 react-word-counter/tsconfig.json delete mode 100644 react-word-counter/tsconfig.node.json delete mode 100644 react-word-counter/vite.config.ts delete mode 100644 react-yjs/.gitignore delete mode 100644 react-yjs/README.md delete mode 100644 react-yjs/index.html delete mode 100644 react-yjs/package.json delete mode 100644 react-yjs/src/App.tsx delete mode 100644 react-yjs/src/app.css delete mode 100644 react-yjs/src/components/editor/examples/yjs/editor-component.tsx delete mode 100644 react-yjs/src/components/editor/examples/yjs/editor.tsx delete mode 100644 react-yjs/src/components/editor/examples/yjs/extension.ts delete mode 100644 react-yjs/src/components/editor/examples/yjs/index.ts delete mode 100644 react-yjs/src/components/editor/ui/button/button.tsx delete mode 100644 react-yjs/src/components/editor/ui/button/index.ts delete mode 100644 react-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 react-yjs/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 react-yjs/src/components/editor/ui/toolbar/index.ts delete mode 100644 react-yjs/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 react-yjs/src/main.tsx delete mode 100644 react-yjs/tsconfig.app.json delete mode 100644 react-yjs/tsconfig.json delete mode 100644 react-yjs/tsconfig.node.json delete mode 100644 react-yjs/vite.config.ts delete mode 100644 solid-block-handle/.gitignore delete mode 100644 solid-block-handle/README.md delete mode 100644 solid-block-handle/index.html delete mode 100644 solid-block-handle/package.json delete mode 100644 solid-block-handle/src/App.tsx delete mode 100644 solid-block-handle/src/app.css delete mode 100644 solid-block-handle/src/components/editor/examples/block-handle/editor.tsx delete mode 100644 solid-block-handle/src/components/editor/examples/block-handle/extension.ts delete mode 100644 solid-block-handle/src/components/editor/examples/block-handle/index.ts delete mode 100644 solid-block-handle/src/components/editor/sample/sample-doc-block-handle.ts delete mode 100644 solid-block-handle/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 solid-block-handle/src/components/editor/ui/block-handle/index.ts delete mode 100644 solid-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 solid-block-handle/src/components/editor/ui/code-block-view/index.ts delete mode 100644 solid-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 solid-block-handle/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 solid-block-handle/src/index.tsx delete mode 100644 solid-block-handle/tsconfig.app.json delete mode 100644 solid-block-handle/tsconfig.json delete mode 100644 solid-block-handle/tsconfig.node.json delete mode 100644 solid-block-handle/vite.config.ts delete mode 100644 solid-blockquote/.gitignore delete mode 100644 solid-blockquote/README.md delete mode 100644 solid-blockquote/index.html delete mode 100644 solid-blockquote/package.json delete mode 100644 solid-blockquote/src/App.tsx delete mode 100644 solid-blockquote/src/app.css delete mode 100644 solid-blockquote/src/components/editor/examples/blockquote/editor.tsx delete mode 100644 solid-blockquote/src/components/editor/examples/blockquote/extension.ts delete mode 100644 solid-blockquote/src/components/editor/examples/blockquote/index.ts delete mode 100644 solid-blockquote/src/components/editor/ui/button/button.tsx delete mode 100644 solid-blockquote/src/components/editor/ui/button/index.ts delete mode 100644 solid-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-blockquote/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-blockquote/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-blockquote/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-blockquote/src/index.tsx delete mode 100644 solid-blockquote/tsconfig.app.json delete mode 100644 solid-blockquote/tsconfig.json delete mode 100644 solid-blockquote/tsconfig.node.json delete mode 100644 solid-blockquote/vite.config.ts delete mode 100644 solid-bold/.gitignore delete mode 100644 solid-bold/README.md delete mode 100644 solid-bold/index.html delete mode 100644 solid-bold/package.json delete mode 100644 solid-bold/src/App.tsx delete mode 100644 solid-bold/src/app.css delete mode 100644 solid-bold/src/components/editor/examples/bold/editor.tsx delete mode 100644 solid-bold/src/components/editor/examples/bold/extension.ts delete mode 100644 solid-bold/src/components/editor/examples/bold/index.ts delete mode 100644 solid-bold/src/components/editor/sample/sample-doc-bold.ts delete mode 100644 solid-bold/src/components/editor/ui/button/button.tsx delete mode 100644 solid-bold/src/components/editor/ui/button/index.ts delete mode 100644 solid-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-bold/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-bold/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-bold/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-bold/src/index.tsx delete mode 100644 solid-bold/tsconfig.app.json delete mode 100644 solid-bold/tsconfig.json delete mode 100644 solid-bold/tsconfig.node.json delete mode 100644 solid-bold/vite.config.ts delete mode 100644 solid-change-tracking/.gitignore delete mode 100644 solid-change-tracking/README.md delete mode 100644 solid-change-tracking/index.html delete mode 100644 solid-change-tracking/package.json delete mode 100644 solid-change-tracking/src/App.tsx delete mode 100644 solid-change-tracking/src/app.css delete mode 100644 solid-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx delete mode 100644 solid-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx delete mode 100644 solid-change-tracking/src/components/editor/examples/change-tracking/editor.tsx delete mode 100644 solid-change-tracking/src/components/editor/examples/change-tracking/index.ts delete mode 100644 solid-change-tracking/src/index.tsx delete mode 100644 solid-change-tracking/tsconfig.app.json delete mode 100644 solid-change-tracking/tsconfig.json delete mode 100644 solid-change-tracking/tsconfig.node.json delete mode 100644 solid-change-tracking/vite.config.ts delete mode 100644 solid-code-block-themes/.gitignore delete mode 100644 solid-code-block-themes/README.md delete mode 100644 solid-code-block-themes/index.html delete mode 100644 solid-code-block-themes/package.json delete mode 100644 solid-code-block-themes/src/App.tsx delete mode 100644 solid-code-block-themes/src/app.css delete mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx delete mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts delete mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/index.ts delete mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx delete mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx delete mode 100644 solid-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 solid-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 solid-code-block-themes/src/components/editor/ui/code-block-view/index.ts delete mode 100644 solid-code-block-themes/src/index.tsx delete mode 100644 solid-code-block-themes/tsconfig.app.json delete mode 100644 solid-code-block-themes/tsconfig.json delete mode 100644 solid-code-block-themes/tsconfig.node.json delete mode 100644 solid-code-block-themes/vite.config.ts delete mode 100644 solid-code-block/.gitignore delete mode 100644 solid-code-block/README.md delete mode 100644 solid-code-block/index.html delete mode 100644 solid-code-block/package.json delete mode 100644 solid-code-block/src/App.tsx delete mode 100644 solid-code-block/src/app.css delete mode 100644 solid-code-block/src/components/editor/examples/code-block/editor.tsx delete mode 100644 solid-code-block/src/components/editor/examples/code-block/extension.ts delete mode 100644 solid-code-block/src/components/editor/examples/code-block/index.ts delete mode 100644 solid-code-block/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 solid-code-block/src/components/editor/ui/button/button.tsx delete mode 100644 solid-code-block/src/components/editor/ui/button/index.ts delete mode 100644 solid-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 solid-code-block/src/components/editor/ui/code-block-view/index.ts delete mode 100644 solid-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-code-block/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-code-block/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-code-block/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-code-block/src/index.tsx delete mode 100644 solid-code-block/tsconfig.app.json delete mode 100644 solid-code-block/tsconfig.json delete mode 100644 solid-code-block/tsconfig.node.json delete mode 100644 solid-code-block/vite.config.ts delete mode 100644 solid-code/.gitignore delete mode 100644 solid-code/README.md delete mode 100644 solid-code/index.html delete mode 100644 solid-code/package.json delete mode 100644 solid-code/src/App.tsx delete mode 100644 solid-code/src/app.css delete mode 100644 solid-code/src/components/editor/examples/code/editor.tsx delete mode 100644 solid-code/src/components/editor/examples/code/extension.ts delete mode 100644 solid-code/src/components/editor/examples/code/index.ts delete mode 100644 solid-code/src/components/editor/sample/sample-doc-code.ts delete mode 100644 solid-code/src/components/editor/ui/button/button.tsx delete mode 100644 solid-code/src/components/editor/ui/button/index.ts delete mode 100644 solid-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-code/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-code/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-code/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-code/src/index.tsx delete mode 100644 solid-code/tsconfig.app.json delete mode 100644 solid-code/tsconfig.json delete mode 100644 solid-code/tsconfig.node.json delete mode 100644 solid-code/vite.config.ts delete mode 100644 solid-drop-cursor/.gitignore delete mode 100644 solid-drop-cursor/README.md delete mode 100644 solid-drop-cursor/index.html delete mode 100644 solid-drop-cursor/package.json delete mode 100644 solid-drop-cursor/src/App.tsx delete mode 100644 solid-drop-cursor/src/app.css delete mode 100644 solid-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx delete mode 100644 solid-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts delete mode 100644 solid-drop-cursor/src/components/editor/examples/drop-cursor/index.ts delete mode 100644 solid-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts delete mode 100644 solid-drop-cursor/src/index.tsx delete mode 100644 solid-drop-cursor/tsconfig.app.json delete mode 100644 solid-drop-cursor/tsconfig.json delete mode 100644 solid-drop-cursor/tsconfig.node.json delete mode 100644 solid-drop-cursor/vite.config.ts delete mode 100644 solid-emoji-rules/.gitignore delete mode 100644 solid-emoji-rules/README.md delete mode 100644 solid-emoji-rules/index.html delete mode 100644 solid-emoji-rules/package.json delete mode 100644 solid-emoji-rules/src/App.tsx delete mode 100644 solid-emoji-rules/src/app.css delete mode 100644 solid-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx delete mode 100644 solid-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts delete mode 100644 solid-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts delete mode 100644 solid-emoji-rules/src/components/editor/examples/emoji-rules/index.ts delete mode 100644 solid-emoji-rules/src/index.tsx delete mode 100644 solid-emoji-rules/tsconfig.app.json delete mode 100644 solid-emoji-rules/tsconfig.json delete mode 100644 solid-emoji-rules/tsconfig.node.json delete mode 100644 solid-emoji-rules/vite.config.ts delete mode 100644 solid-full/.gitignore delete mode 100644 solid-full/README.md delete mode 100644 solid-full/index.html delete mode 100644 solid-full/package.json delete mode 100644 solid-full/src/App.tsx delete mode 100644 solid-full/src/app.css delete mode 100644 solid-full/src/components/editor/examples/full/editor.tsx delete mode 100644 solid-full/src/components/editor/examples/full/extension.ts delete mode 100644 solid-full/src/components/editor/examples/full/index.ts delete mode 100644 solid-full/src/components/editor/sample/katex.ts delete mode 100644 solid-full/src/components/editor/sample/sample-doc-full.ts delete mode 100644 solid-full/src/components/editor/sample/sample-tag-data.ts delete mode 100644 solid-full/src/components/editor/sample/sample-uploader.ts delete mode 100644 solid-full/src/components/editor/sample/sample-user-data.ts delete mode 100644 solid-full/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 solid-full/src/components/editor/ui/block-handle/index.ts delete mode 100644 solid-full/src/components/editor/ui/button/button.tsx delete mode 100644 solid-full/src/components/editor/ui/button/index.ts delete mode 100644 solid-full/src/components/editor/ui/code-block-view/code-block-view.tsx delete mode 100644 solid-full/src/components/editor/ui/code-block-view/index.ts delete mode 100644 solid-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 solid-full/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 solid-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-full/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-full/src/components/editor/ui/image-view/image-view.tsx delete mode 100644 solid-full/src/components/editor/ui/image-view/index.ts delete mode 100644 solid-full/src/components/editor/ui/inline-menu/index.ts delete mode 100644 solid-full/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 solid-full/src/components/editor/ui/slash-menu/index.ts delete mode 100644 solid-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 solid-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 solid-full/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 solid-full/src/components/editor/ui/table-handle/index.ts delete mode 100644 solid-full/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 solid-full/src/components/editor/ui/tag-menu/index.ts delete mode 100644 solid-full/src/components/editor/ui/tag-menu/tag-menu.tsx delete mode 100644 solid-full/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-full/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-full/src/components/editor/ui/user-menu/index.ts delete mode 100644 solid-full/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 solid-full/src/index.tsx delete mode 100644 solid-full/tsconfig.app.json delete mode 100644 solid-full/tsconfig.json delete mode 100644 solid-full/tsconfig.node.json delete mode 100644 solid-full/vite.config.ts delete mode 100644 solid-gap-cursor/.gitignore delete mode 100644 solid-gap-cursor/README.md delete mode 100644 solid-gap-cursor/index.html delete mode 100644 solid-gap-cursor/package.json delete mode 100644 solid-gap-cursor/src/App.tsx delete mode 100644 solid-gap-cursor/src/app.css delete mode 100644 solid-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx delete mode 100644 solid-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts delete mode 100644 solid-gap-cursor/src/components/editor/examples/gap-cursor/index.ts delete mode 100644 solid-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts delete mode 100644 solid-gap-cursor/src/index.tsx delete mode 100644 solid-gap-cursor/tsconfig.app.json delete mode 100644 solid-gap-cursor/tsconfig.json delete mode 100644 solid-gap-cursor/tsconfig.node.json delete mode 100644 solid-gap-cursor/vite.config.ts delete mode 100644 solid-hard-break/.gitignore delete mode 100644 solid-hard-break/README.md delete mode 100644 solid-hard-break/index.html delete mode 100644 solid-hard-break/package.json delete mode 100644 solid-hard-break/src/App.tsx delete mode 100644 solid-hard-break/src/app.css delete mode 100644 solid-hard-break/src/components/editor/examples/hard-break/editor.tsx delete mode 100644 solid-hard-break/src/components/editor/examples/hard-break/extension.ts delete mode 100644 solid-hard-break/src/components/editor/examples/hard-break/index.ts delete mode 100644 solid-hard-break/src/components/editor/examples/hard-break/toolbar.tsx delete mode 100644 solid-hard-break/src/components/editor/sample/sample-doc-hard-break.ts delete mode 100644 solid-hard-break/src/components/editor/ui/button/button.tsx delete mode 100644 solid-hard-break/src/components/editor/ui/button/index.ts delete mode 100644 solid-hard-break/src/index.tsx delete mode 100644 solid-hard-break/tsconfig.app.json delete mode 100644 solid-hard-break/tsconfig.json delete mode 100644 solid-hard-break/tsconfig.node.json delete mode 100644 solid-hard-break/vite.config.ts delete mode 100644 solid-heading/.gitignore delete mode 100644 solid-heading/README.md delete mode 100644 solid-heading/index.html delete mode 100644 solid-heading/package.json delete mode 100644 solid-heading/src/App.tsx delete mode 100644 solid-heading/src/app.css delete mode 100644 solid-heading/src/components/editor/examples/heading/editor.tsx delete mode 100644 solid-heading/src/components/editor/examples/heading/extension.ts delete mode 100644 solid-heading/src/components/editor/examples/heading/index.ts delete mode 100644 solid-heading/src/components/editor/sample/sample-doc-heading.ts delete mode 100644 solid-heading/src/components/editor/ui/button/button.tsx delete mode 100644 solid-heading/src/components/editor/ui/button/index.ts delete mode 100644 solid-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-heading/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-heading/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-heading/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-heading/src/index.tsx delete mode 100644 solid-heading/tsconfig.app.json delete mode 100644 solid-heading/tsconfig.json delete mode 100644 solid-heading/tsconfig.node.json delete mode 100644 solid-heading/vite.config.ts delete mode 100644 solid-highlight/.gitignore delete mode 100644 solid-highlight/README.md delete mode 100644 solid-highlight/index.html delete mode 100644 solid-highlight/package.json delete mode 100644 solid-highlight/src/App.tsx delete mode 100644 solid-highlight/src/app.css delete mode 100644 solid-highlight/src/components/editor/examples/highlight/editor.tsx delete mode 100644 solid-highlight/src/components/editor/examples/highlight/extension.ts delete mode 100644 solid-highlight/src/components/editor/examples/highlight/index.ts delete mode 100644 solid-highlight/src/components/editor/examples/highlight/toolbar.tsx delete mode 100644 solid-highlight/src/components/editor/sample/sample-doc-highlight.ts delete mode 100644 solid-highlight/src/components/editor/ui/button/button.tsx delete mode 100644 solid-highlight/src/components/editor/ui/button/index.ts delete mode 100644 solid-highlight/src/index.tsx delete mode 100644 solid-highlight/tsconfig.app.json delete mode 100644 solid-highlight/tsconfig.json delete mode 100644 solid-highlight/tsconfig.node.json delete mode 100644 solid-highlight/vite.config.ts delete mode 100644 solid-horizontal-rule/.gitignore delete mode 100644 solid-horizontal-rule/README.md delete mode 100644 solid-horizontal-rule/index.html delete mode 100644 solid-horizontal-rule/package.json delete mode 100644 solid-horizontal-rule/src/App.tsx delete mode 100644 solid-horizontal-rule/src/app.css delete mode 100644 solid-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx delete mode 100644 solid-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts delete mode 100644 solid-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts delete mode 100644 solid-horizontal-rule/src/components/editor/ui/button/button.tsx delete mode 100644 solid-horizontal-rule/src/components/editor/ui/button/index.ts delete mode 100644 solid-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-horizontal-rule/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-horizontal-rule/src/index.tsx delete mode 100644 solid-horizontal-rule/tsconfig.app.json delete mode 100644 solid-horizontal-rule/tsconfig.json delete mode 100644 solid-horizontal-rule/tsconfig.node.json delete mode 100644 solid-horizontal-rule/vite.config.ts delete mode 100644 solid-image-view/.gitignore delete mode 100644 solid-image-view/README.md delete mode 100644 solid-image-view/index.html delete mode 100644 solid-image-view/package.json delete mode 100644 solid-image-view/src/App.tsx delete mode 100644 solid-image-view/src/app.css delete mode 100644 solid-image-view/src/components/editor/examples/image-view/editor.tsx delete mode 100644 solid-image-view/src/components/editor/examples/image-view/extension.ts delete mode 100644 solid-image-view/src/components/editor/examples/image-view/index.ts delete mode 100644 solid-image-view/src/components/editor/sample/sample-doc-image.ts delete mode 100644 solid-image-view/src/components/editor/sample/sample-uploader.ts delete mode 100644 solid-image-view/src/components/editor/ui/image-view/image-view.tsx delete mode 100644 solid-image-view/src/components/editor/ui/image-view/index.ts delete mode 100644 solid-image-view/src/index.tsx delete mode 100644 solid-image-view/tsconfig.app.json delete mode 100644 solid-image-view/tsconfig.json delete mode 100644 solid-image-view/tsconfig.node.json delete mode 100644 solid-image-view/vite.config.ts delete mode 100644 solid-inline-menu/.gitignore delete mode 100644 solid-inline-menu/README.md delete mode 100644 solid-inline-menu/index.html delete mode 100644 solid-inline-menu/package.json delete mode 100644 solid-inline-menu/src/App.tsx delete mode 100644 solid-inline-menu/src/app.css delete mode 100644 solid-inline-menu/src/components/editor/examples/inline-menu/editor.tsx delete mode 100644 solid-inline-menu/src/components/editor/examples/inline-menu/extension.ts delete mode 100644 solid-inline-menu/src/components/editor/examples/inline-menu/index.ts delete mode 100644 solid-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts delete mode 100644 solid-inline-menu/src/components/editor/ui/button/button.tsx delete mode 100644 solid-inline-menu/src/components/editor/ui/button/index.ts delete mode 100644 solid-inline-menu/src/components/editor/ui/inline-menu/index.ts delete mode 100644 solid-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 solid-inline-menu/src/index.tsx delete mode 100644 solid-inline-menu/tsconfig.app.json delete mode 100644 solid-inline-menu/tsconfig.json delete mode 100644 solid-inline-menu/tsconfig.node.json delete mode 100644 solid-inline-menu/vite.config.ts delete mode 100644 solid-italic/.gitignore delete mode 100644 solid-italic/README.md delete mode 100644 solid-italic/index.html delete mode 100644 solid-italic/package.json delete mode 100644 solid-italic/src/App.tsx delete mode 100644 solid-italic/src/app.css delete mode 100644 solid-italic/src/components/editor/examples/italic/editor.tsx delete mode 100644 solid-italic/src/components/editor/examples/italic/extension.ts delete mode 100644 solid-italic/src/components/editor/examples/italic/index.ts delete mode 100644 solid-italic/src/components/editor/sample/sample-doc-italic.ts delete mode 100644 solid-italic/src/components/editor/ui/button/button.tsx delete mode 100644 solid-italic/src/components/editor/ui/button/index.ts delete mode 100644 solid-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-italic/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-italic/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-italic/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-italic/src/index.tsx delete mode 100644 solid-italic/tsconfig.app.json delete mode 100644 solid-italic/tsconfig.json delete mode 100644 solid-italic/tsconfig.node.json delete mode 100644 solid-italic/vite.config.ts delete mode 100644 solid-katex/.gitignore delete mode 100644 solid-katex/README.md delete mode 100644 solid-katex/index.html delete mode 100644 solid-katex/package.json delete mode 100644 solid-katex/src/App.tsx delete mode 100644 solid-katex/src/app.css delete mode 100644 solid-katex/src/components/editor/examples/katex/editor.tsx delete mode 100644 solid-katex/src/components/editor/examples/katex/extension.ts delete mode 100644 solid-katex/src/components/editor/examples/katex/index.ts delete mode 100644 solid-katex/src/components/editor/sample/katex.ts delete mode 100644 solid-katex/src/components/editor/sample/sample-doc-tex.ts delete mode 100644 solid-katex/src/index.tsx delete mode 100644 solid-katex/tsconfig.app.json delete mode 100644 solid-katex/tsconfig.json delete mode 100644 solid-katex/tsconfig.node.json delete mode 100644 solid-katex/vite.config.ts delete mode 100644 solid-keymap/.gitignore delete mode 100644 solid-keymap/README.md delete mode 100644 solid-keymap/index.html delete mode 100644 solid-keymap/package.json delete mode 100644 solid-keymap/src/App.tsx delete mode 100644 solid-keymap/src/app.css delete mode 100644 solid-keymap/src/components/editor/examples/keymap/editor.tsx delete mode 100644 solid-keymap/src/components/editor/examples/keymap/extension.ts delete mode 100644 solid-keymap/src/components/editor/examples/keymap/index.ts delete mode 100644 solid-keymap/src/components/editor/examples/keymap/toolbar.tsx delete mode 100644 solid-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts delete mode 100644 solid-keymap/src/components/editor/ui/button/button.tsx delete mode 100644 solid-keymap/src/components/editor/ui/button/index.ts delete mode 100644 solid-keymap/src/index.tsx delete mode 100644 solid-keymap/tsconfig.app.json delete mode 100644 solid-keymap/tsconfig.json delete mode 100644 solid-keymap/tsconfig.node.json delete mode 100644 solid-keymap/vite.config.ts delete mode 100644 solid-link-mark-view/.gitignore delete mode 100644 solid-link-mark-view/README.md delete mode 100644 solid-link-mark-view/index.html delete mode 100644 solid-link-mark-view/package.json delete mode 100644 solid-link-mark-view/src/App.tsx delete mode 100644 solid-link-mark-view/src/app.css delete mode 100644 solid-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx delete mode 100644 solid-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts delete mode 100644 solid-link-mark-view/src/components/editor/examples/link-mark-view/index.ts delete mode 100644 solid-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx delete mode 100644 solid-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts delete mode 100644 solid-link-mark-view/src/index.tsx delete mode 100644 solid-link-mark-view/tsconfig.app.json delete mode 100644 solid-link-mark-view/tsconfig.json delete mode 100644 solid-link-mark-view/tsconfig.node.json delete mode 100644 solid-link-mark-view/vite.config.ts delete mode 100644 solid-link/.gitignore delete mode 100644 solid-link/README.md delete mode 100644 solid-link/index.html delete mode 100644 solid-link/package.json delete mode 100644 solid-link/src/App.tsx delete mode 100644 solid-link/src/app.css delete mode 100644 solid-link/src/components/editor/examples/link/editor.tsx delete mode 100644 solid-link/src/components/editor/examples/link/extension.ts delete mode 100644 solid-link/src/components/editor/examples/link/index.ts delete mode 100644 solid-link/src/components/editor/sample/sample-doc-link.ts delete mode 100644 solid-link/src/components/editor/ui/button/button.tsx delete mode 100644 solid-link/src/components/editor/ui/button/index.ts delete mode 100644 solid-link/src/components/editor/ui/inline-menu/index.ts delete mode 100644 solid-link/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 solid-link/src/index.tsx delete mode 100644 solid-link/tsconfig.app.json delete mode 100644 solid-link/tsconfig.json delete mode 100644 solid-link/tsconfig.node.json delete mode 100644 solid-link/vite.config.ts delete mode 100644 solid-list-custom-checkbox/.gitignore delete mode 100644 solid-list-custom-checkbox/README.md delete mode 100644 solid-list-custom-checkbox/index.html delete mode 100644 solid-list-custom-checkbox/package.json delete mode 100644 solid-list-custom-checkbox/src/App.tsx delete mode 100644 solid-list-custom-checkbox/src/app.css delete mode 100644 solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css delete mode 100644 solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx delete mode 100644 solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts delete mode 100644 solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts delete mode 100644 solid-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts delete mode 100644 solid-list-custom-checkbox/src/components/editor/ui/button/button.tsx delete mode 100644 solid-list-custom-checkbox/src/components/editor/ui/button/index.ts delete mode 100644 solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-list-custom-checkbox/src/index.tsx delete mode 100644 solid-list-custom-checkbox/tsconfig.app.json delete mode 100644 solid-list-custom-checkbox/tsconfig.json delete mode 100644 solid-list-custom-checkbox/tsconfig.node.json delete mode 100644 solid-list-custom-checkbox/vite.config.ts delete mode 100644 solid-list/.gitignore delete mode 100644 solid-list/README.md delete mode 100644 solid-list/index.html delete mode 100644 solid-list/package.json delete mode 100644 solid-list/src/App.tsx delete mode 100644 solid-list/src/app.css delete mode 100644 solid-list/src/components/editor/examples/list/editor.tsx delete mode 100644 solid-list/src/components/editor/examples/list/extension.ts delete mode 100644 solid-list/src/components/editor/examples/list/index.ts delete mode 100644 solid-list/src/components/editor/sample/sample-doc-list.ts delete mode 100644 solid-list/src/components/editor/ui/button/button.tsx delete mode 100644 solid-list/src/components/editor/ui/button/index.ts delete mode 100644 solid-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-list/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-list/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-list/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-list/src/index.tsx delete mode 100644 solid-list/tsconfig.app.json delete mode 100644 solid-list/tsconfig.json delete mode 100644 solid-list/tsconfig.node.json delete mode 100644 solid-list/vite.config.ts delete mode 100644 solid-loro/.gitignore delete mode 100644 solid-loro/README.md delete mode 100644 solid-loro/index.html delete mode 100644 solid-loro/package.json delete mode 100644 solid-loro/src/App.tsx delete mode 100644 solid-loro/src/app.css delete mode 100644 solid-loro/src/components/editor/examples/loro/editor-component.tsx delete mode 100644 solid-loro/src/components/editor/examples/loro/editor.tsx delete mode 100644 solid-loro/src/components/editor/examples/loro/extension.ts delete mode 100644 solid-loro/src/components/editor/examples/loro/index.ts delete mode 100644 solid-loro/src/components/editor/ui/button/button.tsx delete mode 100644 solid-loro/src/components/editor/ui/button/index.ts delete mode 100644 solid-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-loro/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-loro/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-loro/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-loro/src/index.tsx delete mode 100644 solid-loro/tsconfig.app.json delete mode 100644 solid-loro/tsconfig.json delete mode 100644 solid-loro/tsconfig.node.json delete mode 100644 solid-loro/vite.config.ts delete mode 100644 solid-mark-rule/.gitignore delete mode 100644 solid-mark-rule/README.md delete mode 100644 solid-mark-rule/index.html delete mode 100644 solid-mark-rule/package.json delete mode 100644 solid-mark-rule/src/App.tsx delete mode 100644 solid-mark-rule/src/app.css delete mode 100644 solid-mark-rule/src/components/editor/examples/mark-rule/editor.tsx delete mode 100644 solid-mark-rule/src/components/editor/examples/mark-rule/extension.ts delete mode 100644 solid-mark-rule/src/components/editor/examples/mark-rule/index.ts delete mode 100644 solid-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts delete mode 100644 solid-mark-rule/src/index.tsx delete mode 100644 solid-mark-rule/tsconfig.app.json delete mode 100644 solid-mark-rule/tsconfig.json delete mode 100644 solid-mark-rule/tsconfig.node.json delete mode 100644 solid-mark-rule/vite.config.ts delete mode 100644 solid-minimal/.gitignore delete mode 100644 solid-minimal/README.md delete mode 100644 solid-minimal/index.html delete mode 100644 solid-minimal/package.json delete mode 100644 solid-minimal/src/App.tsx delete mode 100644 solid-minimal/src/app.css delete mode 100644 solid-minimal/src/components/editor/examples/minimal/editor.tsx delete mode 100644 solid-minimal/src/components/editor/examples/minimal/index.ts delete mode 100644 solid-minimal/src/index.tsx delete mode 100644 solid-minimal/tsconfig.app.json delete mode 100644 solid-minimal/tsconfig.json delete mode 100644 solid-minimal/tsconfig.node.json delete mode 100644 solid-minimal/vite.config.ts delete mode 100644 solid-placeholder/.gitignore delete mode 100644 solid-placeholder/README.md delete mode 100644 solid-placeholder/index.html delete mode 100644 solid-placeholder/package.json delete mode 100644 solid-placeholder/src/App.tsx delete mode 100644 solid-placeholder/src/app.css delete mode 100644 solid-placeholder/src/components/editor/examples/placeholder/editor.tsx delete mode 100644 solid-placeholder/src/components/editor/examples/placeholder/extension.ts delete mode 100644 solid-placeholder/src/components/editor/examples/placeholder/index.ts delete mode 100644 solid-placeholder/src/index.tsx delete mode 100644 solid-placeholder/tsconfig.app.json delete mode 100644 solid-placeholder/tsconfig.json delete mode 100644 solid-placeholder/tsconfig.node.json delete mode 100644 solid-placeholder/vite.config.ts delete mode 100644 solid-readonly/.gitignore delete mode 100644 solid-readonly/README.md delete mode 100644 solid-readonly/index.html delete mode 100644 solid-readonly/package.json delete mode 100644 solid-readonly/src/App.tsx delete mode 100644 solid-readonly/src/app.css delete mode 100644 solid-readonly/src/components/editor/examples/readonly/editor.tsx delete mode 100644 solid-readonly/src/components/editor/examples/readonly/extension.ts delete mode 100644 solid-readonly/src/components/editor/examples/readonly/index.ts delete mode 100644 solid-readonly/src/components/editor/examples/readonly/toolbar.tsx delete mode 100644 solid-readonly/src/components/editor/examples/readonly/use-readonly.ts delete mode 100644 solid-readonly/src/components/editor/sample/sample-doc-readonly.ts delete mode 100644 solid-readonly/src/components/editor/ui/button/button.tsx delete mode 100644 solid-readonly/src/components/editor/ui/button/index.ts delete mode 100644 solid-readonly/src/index.tsx delete mode 100644 solid-readonly/tsconfig.app.json delete mode 100644 solid-readonly/tsconfig.json delete mode 100644 solid-readonly/tsconfig.node.json delete mode 100644 solid-readonly/vite.config.ts delete mode 100644 solid-rtl/.gitignore delete mode 100644 solid-rtl/README.md delete mode 100644 solid-rtl/index.html delete mode 100644 solid-rtl/package.json delete mode 100644 solid-rtl/src/App.tsx delete mode 100644 solid-rtl/src/app.css delete mode 100644 solid-rtl/src/components/editor/examples/rtl/editor.tsx delete mode 100644 solid-rtl/src/components/editor/examples/rtl/index.ts delete mode 100644 solid-rtl/src/components/editor/sample/sample-doc-rtl.ts delete mode 100644 solid-rtl/src/components/editor/sample/sample-uploader.ts delete mode 100644 solid-rtl/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 solid-rtl/src/components/editor/ui/block-handle/index.ts delete mode 100644 solid-rtl/src/components/editor/ui/button/button.tsx delete mode 100644 solid-rtl/src/components/editor/ui/button/index.ts delete mode 100644 solid-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 solid-rtl/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 solid-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-rtl/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-rtl/src/components/editor/ui/inline-menu/index.ts delete mode 100644 solid-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 solid-rtl/src/components/editor/ui/slash-menu/index.ts delete mode 100644 solid-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 solid-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 solid-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 solid-rtl/src/components/editor/ui/table-handle/index.ts delete mode 100644 solid-rtl/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 solid-rtl/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-rtl/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-rtl/src/index.tsx delete mode 100644 solid-rtl/tsconfig.app.json delete mode 100644 solid-rtl/tsconfig.json delete mode 100644 solid-rtl/tsconfig.node.json delete mode 100644 solid-rtl/vite.config.ts delete mode 100644 solid-save-html/.gitignore delete mode 100644 solid-save-html/README.md delete mode 100644 solid-save-html/index.html delete mode 100644 solid-save-html/package.json delete mode 100644 solid-save-html/src/App.tsx delete mode 100644 solid-save-html/src/app.css delete mode 100644 solid-save-html/src/components/editor/examples/save-html/editor.tsx delete mode 100644 solid-save-html/src/components/editor/examples/save-html/index.ts delete mode 100644 solid-save-html/src/index.tsx delete mode 100644 solid-save-html/tsconfig.app.json delete mode 100644 solid-save-html/tsconfig.json delete mode 100644 solid-save-html/tsconfig.node.json delete mode 100644 solid-save-html/vite.config.ts delete mode 100644 solid-save-json/.gitignore delete mode 100644 solid-save-json/README.md delete mode 100644 solid-save-json/index.html delete mode 100644 solid-save-json/package.json delete mode 100644 solid-save-json/src/App.tsx delete mode 100644 solid-save-json/src/app.css delete mode 100644 solid-save-json/src/components/editor/examples/save-json/editor.tsx delete mode 100644 solid-save-json/src/components/editor/examples/save-json/index.ts delete mode 100644 solid-save-json/src/index.tsx delete mode 100644 solid-save-json/tsconfig.app.json delete mode 100644 solid-save-json/tsconfig.json delete mode 100644 solid-save-json/tsconfig.node.json delete mode 100644 solid-save-json/vite.config.ts delete mode 100644 solid-save-markdown/.gitignore delete mode 100644 solid-save-markdown/README.md delete mode 100644 solid-save-markdown/index.html delete mode 100644 solid-save-markdown/package.json delete mode 100644 solid-save-markdown/src/App.tsx delete mode 100644 solid-save-markdown/src/app.css delete mode 100644 solid-save-markdown/src/components/editor/examples/save-markdown/editor.tsx delete mode 100644 solid-save-markdown/src/components/editor/examples/save-markdown/index.ts delete mode 100644 solid-save-markdown/src/components/editor/examples/save-markdown/markdown.ts delete mode 100644 solid-save-markdown/src/index.tsx delete mode 100644 solid-save-markdown/tsconfig.app.json delete mode 100644 solid-save-markdown/tsconfig.json delete mode 100644 solid-save-markdown/tsconfig.node.json delete mode 100644 solid-save-markdown/vite.config.ts delete mode 100644 solid-search/.gitignore delete mode 100644 solid-search/README.md delete mode 100644 solid-search/index.html delete mode 100644 solid-search/package.json delete mode 100644 solid-search/src/App.tsx delete mode 100644 solid-search/src/app.css delete mode 100644 solid-search/src/components/editor/examples/search/editor.tsx delete mode 100644 solid-search/src/components/editor/examples/search/extension.ts delete mode 100644 solid-search/src/components/editor/examples/search/index.ts delete mode 100644 solid-search/src/components/editor/sample/sample-doc-search.ts delete mode 100644 solid-search/src/components/editor/ui/button/button.tsx delete mode 100644 solid-search/src/components/editor/ui/button/index.ts delete mode 100644 solid-search/src/components/editor/ui/search/index.ts delete mode 100644 solid-search/src/components/editor/ui/search/search.tsx delete mode 100644 solid-search/src/index.tsx delete mode 100644 solid-search/tsconfig.app.json delete mode 100644 solid-search/tsconfig.json delete mode 100644 solid-search/tsconfig.node.json delete mode 100644 solid-search/vite.config.ts delete mode 100644 solid-slash-menu/.gitignore delete mode 100644 solid-slash-menu/README.md delete mode 100644 solid-slash-menu/index.html delete mode 100644 solid-slash-menu/package.json delete mode 100644 solid-slash-menu/src/App.tsx delete mode 100644 solid-slash-menu/src/app.css delete mode 100644 solid-slash-menu/src/components/editor/examples/slash-menu/editor.tsx delete mode 100644 solid-slash-menu/src/components/editor/examples/slash-menu/extension.ts delete mode 100644 solid-slash-menu/src/components/editor/examples/slash-menu/index.ts delete mode 100644 solid-slash-menu/src/components/editor/ui/slash-menu/index.ts delete mode 100644 solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx delete mode 100644 solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx delete mode 100644 solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx delete mode 100644 solid-slash-menu/src/index.tsx delete mode 100644 solid-slash-menu/tsconfig.app.json delete mode 100644 solid-slash-menu/tsconfig.json delete mode 100644 solid-slash-menu/tsconfig.node.json delete mode 100644 solid-slash-menu/vite.config.ts delete mode 100644 solid-strike/.gitignore delete mode 100644 solid-strike/README.md delete mode 100644 solid-strike/index.html delete mode 100644 solid-strike/package.json delete mode 100644 solid-strike/src/App.tsx delete mode 100644 solid-strike/src/app.css delete mode 100644 solid-strike/src/components/editor/examples/strike/editor.tsx delete mode 100644 solid-strike/src/components/editor/examples/strike/extension.ts delete mode 100644 solid-strike/src/components/editor/examples/strike/index.ts delete mode 100644 solid-strike/src/components/editor/examples/strike/toolbar.tsx delete mode 100644 solid-strike/src/components/editor/sample/sample-doc-strike.ts delete mode 100644 solid-strike/src/components/editor/ui/button/button.tsx delete mode 100644 solid-strike/src/components/editor/ui/button/index.ts delete mode 100644 solid-strike/src/index.tsx delete mode 100644 solid-strike/tsconfig.app.json delete mode 100644 solid-strike/tsconfig.json delete mode 100644 solid-strike/tsconfig.node.json delete mode 100644 solid-strike/vite.config.ts delete mode 100644 solid-sub-sup/.gitignore delete mode 100644 solid-sub-sup/README.md delete mode 100644 solid-sub-sup/index.html delete mode 100644 solid-sub-sup/package.json delete mode 100644 solid-sub-sup/src/App.tsx delete mode 100644 solid-sub-sup/src/app.css delete mode 100644 solid-sub-sup/src/components/editor/examples/sub-sup/editor.tsx delete mode 100644 solid-sub-sup/src/components/editor/examples/sub-sup/extension.ts delete mode 100644 solid-sub-sup/src/components/editor/examples/sub-sup/index.ts delete mode 100644 solid-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx delete mode 100644 solid-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts delete mode 100644 solid-sub-sup/src/components/editor/ui/button/button.tsx delete mode 100644 solid-sub-sup/src/components/editor/ui/button/index.ts delete mode 100644 solid-sub-sup/src/index.tsx delete mode 100644 solid-sub-sup/tsconfig.app.json delete mode 100644 solid-sub-sup/tsconfig.json delete mode 100644 solid-sub-sup/tsconfig.node.json delete mode 100644 solid-sub-sup/vite.config.ts delete mode 100644 solid-table/.gitignore delete mode 100644 solid-table/README.md delete mode 100644 solid-table/index.html delete mode 100644 solid-table/package.json delete mode 100644 solid-table/src/App.tsx delete mode 100644 solid-table/src/app.css delete mode 100644 solid-table/src/components/editor/examples/table/editor.tsx delete mode 100644 solid-table/src/components/editor/examples/table/extension.ts delete mode 100644 solid-table/src/components/editor/examples/table/index.ts delete mode 100644 solid-table/src/components/editor/sample/sample-doc-table.ts delete mode 100644 solid-table/src/components/editor/ui/table-handle/index.ts delete mode 100644 solid-table/src/components/editor/ui/table-handle/table-handle.tsx delete mode 100644 solid-table/src/index.tsx delete mode 100644 solid-table/tsconfig.app.json delete mode 100644 solid-table/tsconfig.json delete mode 100644 solid-table/tsconfig.node.json delete mode 100644 solid-table/vite.config.ts delete mode 100644 solid-temml/.gitignore delete mode 100644 solid-temml/README.md delete mode 100644 solid-temml/index.html delete mode 100644 solid-temml/package.json delete mode 100644 solid-temml/src/App.tsx delete mode 100644 solid-temml/src/app.css delete mode 100644 solid-temml/src/components/editor/examples/temml/editor.tsx delete mode 100644 solid-temml/src/components/editor/examples/temml/extension.ts delete mode 100644 solid-temml/src/components/editor/examples/temml/index.ts delete mode 100644 solid-temml/src/components/editor/sample/sample-doc-tex.ts delete mode 100644 solid-temml/src/components/editor/sample/temml.ts delete mode 100644 solid-temml/src/index.tsx delete mode 100644 solid-temml/tsconfig.app.json delete mode 100644 solid-temml/tsconfig.json delete mode 100644 solid-temml/tsconfig.node.json delete mode 100644 solid-temml/vite.config.ts delete mode 100644 solid-text-align/.gitignore delete mode 100644 solid-text-align/README.md delete mode 100644 solid-text-align/index.html delete mode 100644 solid-text-align/package.json delete mode 100644 solid-text-align/src/App.tsx delete mode 100644 solid-text-align/src/app.css delete mode 100644 solid-text-align/src/components/editor/examples/text-align/editor.tsx delete mode 100644 solid-text-align/src/components/editor/examples/text-align/extension.ts delete mode 100644 solid-text-align/src/components/editor/examples/text-align/index.ts delete mode 100644 solid-text-align/src/components/editor/examples/text-align/toolbar.tsx delete mode 100644 solid-text-align/src/components/editor/sample/sample-doc-text-align.ts delete mode 100644 solid-text-align/src/components/editor/ui/button/button.tsx delete mode 100644 solid-text-align/src/components/editor/ui/button/index.ts delete mode 100644 solid-text-align/src/index.tsx delete mode 100644 solid-text-align/tsconfig.app.json delete mode 100644 solid-text-align/tsconfig.json delete mode 100644 solid-text-align/tsconfig.node.json delete mode 100644 solid-text-align/vite.config.ts delete mode 100644 solid-text-color/.gitignore delete mode 100644 solid-text-color/README.md delete mode 100644 solid-text-color/index.html delete mode 100644 solid-text-color/package.json delete mode 100644 solid-text-color/src/App.tsx delete mode 100644 solid-text-color/src/app.css delete mode 100644 solid-text-color/src/components/editor/examples/text-color/editor.tsx delete mode 100644 solid-text-color/src/components/editor/examples/text-color/extension.ts delete mode 100644 solid-text-color/src/components/editor/examples/text-color/index.ts delete mode 100644 solid-text-color/src/components/editor/examples/text-color/inline-menu.tsx delete mode 100644 solid-text-color/src/components/editor/sample/sample-doc-text-color.ts delete mode 100644 solid-text-color/src/components/editor/ui/button/button.tsx delete mode 100644 solid-text-color/src/components/editor/ui/button/index.ts delete mode 100644 solid-text-color/src/index.tsx delete mode 100644 solid-text-color/tsconfig.app.json delete mode 100644 solid-text-color/tsconfig.json delete mode 100644 solid-text-color/tsconfig.node.json delete mode 100644 solid-text-color/vite.config.ts delete mode 100644 solid-toolbar/.gitignore delete mode 100644 solid-toolbar/README.md delete mode 100644 solid-toolbar/index.html delete mode 100644 solid-toolbar/package.json delete mode 100644 solid-toolbar/src/App.tsx delete mode 100644 solid-toolbar/src/app.css delete mode 100644 solid-toolbar/src/components/editor/examples/toolbar/editor.tsx delete mode 100644 solid-toolbar/src/components/editor/examples/toolbar/extension.ts delete mode 100644 solid-toolbar/src/components/editor/examples/toolbar/index.ts delete mode 100644 solid-toolbar/src/components/editor/sample/sample-uploader.ts delete mode 100644 solid-toolbar/src/components/editor/ui/button/button.tsx delete mode 100644 solid-toolbar/src/components/editor/ui/button/index.ts delete mode 100644 solid-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-toolbar/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-toolbar/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-toolbar/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-toolbar/src/index.tsx delete mode 100644 solid-toolbar/tsconfig.app.json delete mode 100644 solid-toolbar/tsconfig.json delete mode 100644 solid-toolbar/tsconfig.node.json delete mode 100644 solid-toolbar/vite.config.ts delete mode 100644 solid-typography/.gitignore delete mode 100644 solid-typography/README.md delete mode 100644 solid-typography/index.html delete mode 100644 solid-typography/package.json delete mode 100644 solid-typography/src/App.tsx delete mode 100644 solid-typography/src/app.css delete mode 100644 solid-typography/src/components/editor/examples/typography/editor.tsx delete mode 100644 solid-typography/src/components/editor/examples/typography/extension.ts delete mode 100644 solid-typography/src/components/editor/examples/typography/index.ts delete mode 100644 solid-typography/src/components/editor/sample/katex.ts delete mode 100644 solid-typography/src/components/editor/sample/sample-doc-typography.ts delete mode 100644 solid-typography/src/components/editor/ui/block-handle/block-handle.tsx delete mode 100644 solid-typography/src/components/editor/ui/block-handle/index.ts delete mode 100644 solid-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx delete mode 100644 solid-typography/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 solid-typography/src/index.tsx delete mode 100644 solid-typography/tsconfig.app.json delete mode 100644 solid-typography/tsconfig.json delete mode 100644 solid-typography/tsconfig.node.json delete mode 100644 solid-typography/vite.config.ts delete mode 100644 solid-underline/.gitignore delete mode 100644 solid-underline/README.md delete mode 100644 solid-underline/index.html delete mode 100644 solid-underline/package.json delete mode 100644 solid-underline/src/App.tsx delete mode 100644 solid-underline/src/app.css delete mode 100644 solid-underline/src/components/editor/examples/underline/editor.tsx delete mode 100644 solid-underline/src/components/editor/examples/underline/extension.ts delete mode 100644 solid-underline/src/components/editor/examples/underline/index.ts delete mode 100644 solid-underline/src/components/editor/sample/sample-doc-underline.ts delete mode 100644 solid-underline/src/components/editor/ui/button/button.tsx delete mode 100644 solid-underline/src/components/editor/ui/button/index.ts delete mode 100644 solid-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-underline/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-underline/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-underline/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-underline/src/index.tsx delete mode 100644 solid-underline/tsconfig.app.json delete mode 100644 solid-underline/tsconfig.json delete mode 100644 solid-underline/tsconfig.node.json delete mode 100644 solid-underline/vite.config.ts delete mode 100644 solid-unmount/.gitignore delete mode 100644 solid-unmount/README.md delete mode 100644 solid-unmount/index.html delete mode 100644 solid-unmount/package.json delete mode 100644 solid-unmount/src/App.tsx delete mode 100644 solid-unmount/src/app.css delete mode 100644 solid-unmount/src/components/editor/examples/unmount/editor-component.tsx delete mode 100644 solid-unmount/src/components/editor/examples/unmount/editor.tsx delete mode 100644 solid-unmount/src/components/editor/examples/unmount/extension-component.tsx delete mode 100644 solid-unmount/src/components/editor/examples/unmount/index.ts delete mode 100644 solid-unmount/src/components/editor/ui/button/button.tsx delete mode 100644 solid-unmount/src/components/editor/ui/button/index.ts delete mode 100644 solid-unmount/src/components/editor/ui/inline-menu/index.ts delete mode 100644 solid-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx delete mode 100644 solid-unmount/src/index.tsx delete mode 100644 solid-unmount/tsconfig.app.json delete mode 100644 solid-unmount/tsconfig.json delete mode 100644 solid-unmount/tsconfig.node.json delete mode 100644 solid-unmount/vite.config.ts delete mode 100644 solid-user-menu-dynamic/.gitignore delete mode 100644 solid-user-menu-dynamic/README.md delete mode 100644 solid-user-menu-dynamic/index.html delete mode 100644 solid-user-menu-dynamic/package.json delete mode 100644 solid-user-menu-dynamic/src/App.tsx delete mode 100644 solid-user-menu-dynamic/src/app.css delete mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx delete mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts delete mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts delete mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts delete mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx delete mode 100644 solid-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts delete mode 100644 solid-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts delete mode 100644 solid-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts delete mode 100644 solid-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 solid-user-menu-dynamic/src/index.tsx delete mode 100644 solid-user-menu-dynamic/tsconfig.app.json delete mode 100644 solid-user-menu-dynamic/tsconfig.json delete mode 100644 solid-user-menu-dynamic/tsconfig.node.json delete mode 100644 solid-user-menu-dynamic/vite.config.ts delete mode 100644 solid-user-menu/.gitignore delete mode 100644 solid-user-menu/README.md delete mode 100644 solid-user-menu/index.html delete mode 100644 solid-user-menu/package.json delete mode 100644 solid-user-menu/src/App.tsx delete mode 100644 solid-user-menu/src/app.css delete mode 100644 solid-user-menu/src/components/editor/examples/user-menu/editor.tsx delete mode 100644 solid-user-menu/src/components/editor/examples/user-menu/extension.ts delete mode 100644 solid-user-menu/src/components/editor/examples/user-menu/index.ts delete mode 100644 solid-user-menu/src/components/editor/sample/sample-tag-data.ts delete mode 100644 solid-user-menu/src/components/editor/sample/sample-user-data.ts delete mode 100644 solid-user-menu/src/components/editor/ui/tag-menu/index.ts delete mode 100644 solid-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx delete mode 100644 solid-user-menu/src/components/editor/ui/user-menu/index.ts delete mode 100644 solid-user-menu/src/components/editor/ui/user-menu/user-menu.tsx delete mode 100644 solid-user-menu/src/index.tsx delete mode 100644 solid-user-menu/tsconfig.app.json delete mode 100644 solid-user-menu/tsconfig.json delete mode 100644 solid-user-menu/tsconfig.node.json delete mode 100644 solid-user-menu/vite.config.ts delete mode 100644 solid-word-counter/.gitignore delete mode 100644 solid-word-counter/README.md delete mode 100644 solid-word-counter/index.html delete mode 100644 solid-word-counter/package.json delete mode 100644 solid-word-counter/src/App.tsx delete mode 100644 solid-word-counter/src/app.css delete mode 100644 solid-word-counter/src/components/editor/examples/word-counter/editor.tsx delete mode 100644 solid-word-counter/src/components/editor/examples/word-counter/extension.ts delete mode 100644 solid-word-counter/src/components/editor/examples/word-counter/index.ts delete mode 100644 solid-word-counter/src/components/editor/sample/sample-doc-word-counter.ts delete mode 100644 solid-word-counter/src/components/editor/ui/word-counter/index.ts delete mode 100644 solid-word-counter/src/components/editor/ui/word-counter/word-counter.tsx delete mode 100644 solid-word-counter/src/index.tsx delete mode 100644 solid-word-counter/tsconfig.app.json delete mode 100644 solid-word-counter/tsconfig.json delete mode 100644 solid-word-counter/tsconfig.node.json delete mode 100644 solid-word-counter/vite.config.ts delete mode 100644 solid-yjs/.gitignore delete mode 100644 solid-yjs/README.md delete mode 100644 solid-yjs/index.html delete mode 100644 solid-yjs/package.json delete mode 100644 solid-yjs/src/App.tsx delete mode 100644 solid-yjs/src/app.css delete mode 100644 solid-yjs/src/components/editor/examples/yjs/editor-component.tsx delete mode 100644 solid-yjs/src/components/editor/examples/yjs/editor.tsx delete mode 100644 solid-yjs/src/components/editor/examples/yjs/extension.ts delete mode 100644 solid-yjs/src/components/editor/examples/yjs/index.ts delete mode 100644 solid-yjs/src/components/editor/ui/button/button.tsx delete mode 100644 solid-yjs/src/components/editor/ui/button/index.ts delete mode 100644 solid-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx delete mode 100644 solid-yjs/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 solid-yjs/src/components/editor/ui/toolbar/index.ts delete mode 100644 solid-yjs/src/components/editor/ui/toolbar/toolbar.tsx delete mode 100644 solid-yjs/src/index.tsx delete mode 100644 solid-yjs/tsconfig.app.json delete mode 100644 solid-yjs/tsconfig.json delete mode 100644 solid-yjs/tsconfig.node.json delete mode 100644 solid-yjs/vite.config.ts delete mode 100644 svelte-block-handle/.gitignore delete mode 100644 svelte-block-handle/README.md delete mode 100644 svelte-block-handle/index.html delete mode 100644 svelte-block-handle/package.json delete mode 100644 svelte-block-handle/src/App.svelte delete mode 100644 svelte-block-handle/src/app.css delete mode 100644 svelte-block-handle/src/components/editor/examples/block-handle/editor.svelte delete mode 100644 svelte-block-handle/src/components/editor/examples/block-handle/extension.ts delete mode 100644 svelte-block-handle/src/components/editor/examples/block-handle/index.ts delete mode 100644 svelte-block-handle/src/components/editor/sample/sample-doc-block-handle.ts delete mode 100644 svelte-block-handle/src/components/editor/ui/block-handle/block-handle.svelte delete mode 100644 svelte-block-handle/src/components/editor/ui/block-handle/index.ts delete mode 100644 svelte-block-handle/src/components/editor/ui/code-block-view/code-block-view.svelte delete mode 100644 svelte-block-handle/src/components/editor/ui/code-block-view/index.ts delete mode 100644 svelte-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.svelte delete mode 100644 svelte-block-handle/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 svelte-block-handle/src/main.ts delete mode 100644 svelte-block-handle/src/vite-env.d.ts delete mode 100644 svelte-block-handle/svelte.config.js delete mode 100644 svelte-block-handle/tsconfig.json delete mode 100644 svelte-block-handle/tsconfig.node.json delete mode 100644 svelte-block-handle/vite.config.ts delete mode 100644 svelte-blockquote/.gitignore delete mode 100644 svelte-blockquote/README.md delete mode 100644 svelte-blockquote/index.html delete mode 100644 svelte-blockquote/package.json delete mode 100644 svelte-blockquote/src/App.svelte delete mode 100644 svelte-blockquote/src/app.css delete mode 100644 svelte-blockquote/src/components/editor/examples/blockquote/editor.svelte delete mode 100644 svelte-blockquote/src/components/editor/examples/blockquote/extension.ts delete mode 100644 svelte-blockquote/src/components/editor/examples/blockquote/index.ts delete mode 100644 svelte-blockquote/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-blockquote/src/components/editor/ui/button/index.ts delete mode 100644 svelte-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-blockquote/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-blockquote/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-blockquote/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-blockquote/src/main.ts delete mode 100644 svelte-blockquote/src/vite-env.d.ts delete mode 100644 svelte-blockquote/svelte.config.js delete mode 100644 svelte-blockquote/tsconfig.json delete mode 100644 svelte-blockquote/tsconfig.node.json delete mode 100644 svelte-blockquote/vite.config.ts delete mode 100644 svelte-bold/.gitignore delete mode 100644 svelte-bold/README.md delete mode 100644 svelte-bold/index.html delete mode 100644 svelte-bold/package.json delete mode 100644 svelte-bold/src/App.svelte delete mode 100644 svelte-bold/src/app.css delete mode 100644 svelte-bold/src/components/editor/examples/bold/editor.svelte delete mode 100644 svelte-bold/src/components/editor/examples/bold/extension.ts delete mode 100644 svelte-bold/src/components/editor/examples/bold/index.ts delete mode 100644 svelte-bold/src/components/editor/sample/sample-doc-bold.ts delete mode 100644 svelte-bold/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-bold/src/components/editor/ui/button/index.ts delete mode 100644 svelte-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-bold/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-bold/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-bold/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-bold/src/main.ts delete mode 100644 svelte-bold/src/vite-env.d.ts delete mode 100644 svelte-bold/svelte.config.js delete mode 100644 svelte-bold/tsconfig.json delete mode 100644 svelte-bold/tsconfig.node.json delete mode 100644 svelte-bold/vite.config.ts delete mode 100644 svelte-change-tracking/.gitignore delete mode 100644 svelte-change-tracking/README.md delete mode 100644 svelte-change-tracking/index.html delete mode 100644 svelte-change-tracking/package.json delete mode 100644 svelte-change-tracking/src/App.svelte delete mode 100644 svelte-change-tracking/src/app.css delete mode 100644 svelte-change-tracking/src/components/editor/examples/change-tracking/editor-diff.svelte delete mode 100644 svelte-change-tracking/src/components/editor/examples/change-tracking/editor-main.svelte delete mode 100644 svelte-change-tracking/src/components/editor/examples/change-tracking/editor.svelte delete mode 100644 svelte-change-tracking/src/components/editor/examples/change-tracking/index.ts delete mode 100644 svelte-change-tracking/src/main.ts delete mode 100644 svelte-change-tracking/src/vite-env.d.ts delete mode 100644 svelte-change-tracking/svelte.config.js delete mode 100644 svelte-change-tracking/tsconfig.json delete mode 100644 svelte-change-tracking/tsconfig.node.json delete mode 100644 svelte-change-tracking/vite.config.ts delete mode 100644 svelte-code-block-themes/.gitignore delete mode 100644 svelte-code-block-themes/README.md delete mode 100644 svelte-code-block-themes/index.html delete mode 100644 svelte-code-block-themes/package.json delete mode 100644 svelte-code-block-themes/src/App.svelte delete mode 100644 svelte-code-block-themes/src/app.css delete mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/editor.svelte delete mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts delete mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/index.ts delete mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.svelte delete mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.svelte delete mode 100644 svelte-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 svelte-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.svelte delete mode 100644 svelte-code-block-themes/src/components/editor/ui/code-block-view/index.ts delete mode 100644 svelte-code-block-themes/src/main.ts delete mode 100644 svelte-code-block-themes/src/vite-env.d.ts delete mode 100644 svelte-code-block-themes/svelte.config.js delete mode 100644 svelte-code-block-themes/tsconfig.json delete mode 100644 svelte-code-block-themes/tsconfig.node.json delete mode 100644 svelte-code-block-themes/vite.config.ts delete mode 100644 svelte-code-block/.gitignore delete mode 100644 svelte-code-block/README.md delete mode 100644 svelte-code-block/index.html delete mode 100644 svelte-code-block/package.json delete mode 100644 svelte-code-block/src/App.svelte delete mode 100644 svelte-code-block/src/app.css delete mode 100644 svelte-code-block/src/components/editor/examples/code-block/editor.svelte delete mode 100644 svelte-code-block/src/components/editor/examples/code-block/extension.ts delete mode 100644 svelte-code-block/src/components/editor/examples/code-block/index.ts delete mode 100644 svelte-code-block/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 svelte-code-block/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-code-block/src/components/editor/ui/button/index.ts delete mode 100644 svelte-code-block/src/components/editor/ui/code-block-view/code-block-view.svelte delete mode 100644 svelte-code-block/src/components/editor/ui/code-block-view/index.ts delete mode 100644 svelte-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-code-block/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-code-block/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-code-block/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-code-block/src/main.ts delete mode 100644 svelte-code-block/src/vite-env.d.ts delete mode 100644 svelte-code-block/svelte.config.js delete mode 100644 svelte-code-block/tsconfig.json delete mode 100644 svelte-code-block/tsconfig.node.json delete mode 100644 svelte-code-block/vite.config.ts delete mode 100644 svelte-code/.gitignore delete mode 100644 svelte-code/README.md delete mode 100644 svelte-code/index.html delete mode 100644 svelte-code/package.json delete mode 100644 svelte-code/src/App.svelte delete mode 100644 svelte-code/src/app.css delete mode 100644 svelte-code/src/components/editor/examples/code/editor.svelte delete mode 100644 svelte-code/src/components/editor/examples/code/extension.ts delete mode 100644 svelte-code/src/components/editor/examples/code/index.ts delete mode 100644 svelte-code/src/components/editor/sample/sample-doc-code.ts delete mode 100644 svelte-code/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-code/src/components/editor/ui/button/index.ts delete mode 100644 svelte-code/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-code/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-code/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-code/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-code/src/main.ts delete mode 100644 svelte-code/src/vite-env.d.ts delete mode 100644 svelte-code/svelte.config.js delete mode 100644 svelte-code/tsconfig.json delete mode 100644 svelte-code/tsconfig.node.json delete mode 100644 svelte-code/vite.config.ts delete mode 100644 svelte-drop-cursor/.gitignore delete mode 100644 svelte-drop-cursor/README.md delete mode 100644 svelte-drop-cursor/index.html delete mode 100644 svelte-drop-cursor/package.json delete mode 100644 svelte-drop-cursor/src/App.svelte delete mode 100644 svelte-drop-cursor/src/app.css delete mode 100644 svelte-drop-cursor/src/components/editor/examples/drop-cursor/editor.svelte delete mode 100644 svelte-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts delete mode 100644 svelte-drop-cursor/src/components/editor/examples/drop-cursor/index.ts delete mode 100644 svelte-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts delete mode 100644 svelte-drop-cursor/src/main.ts delete mode 100644 svelte-drop-cursor/src/vite-env.d.ts delete mode 100644 svelte-drop-cursor/svelte.config.js delete mode 100644 svelte-drop-cursor/tsconfig.json delete mode 100644 svelte-drop-cursor/tsconfig.node.json delete mode 100644 svelte-drop-cursor/vite.config.ts delete mode 100644 svelte-emoji-rules/.gitignore delete mode 100644 svelte-emoji-rules/README.md delete mode 100644 svelte-emoji-rules/index.html delete mode 100644 svelte-emoji-rules/package.json delete mode 100644 svelte-emoji-rules/src/App.svelte delete mode 100644 svelte-emoji-rules/src/app.css delete mode 100644 svelte-emoji-rules/src/components/editor/examples/emoji-rules/editor.svelte delete mode 100644 svelte-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts delete mode 100644 svelte-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts delete mode 100644 svelte-emoji-rules/src/components/editor/examples/emoji-rules/index.ts delete mode 100644 svelte-emoji-rules/src/main.ts delete mode 100644 svelte-emoji-rules/src/vite-env.d.ts delete mode 100644 svelte-emoji-rules/svelte.config.js delete mode 100644 svelte-emoji-rules/tsconfig.json delete mode 100644 svelte-emoji-rules/tsconfig.node.json delete mode 100644 svelte-emoji-rules/vite.config.ts delete mode 100644 svelte-full/.gitignore delete mode 100644 svelte-full/README.md delete mode 100644 svelte-full/index.html delete mode 100644 svelte-full/package.json delete mode 100644 svelte-full/src/App.svelte delete mode 100644 svelte-full/src/app.css delete mode 100644 svelte-full/src/components/editor/examples/full/editor.svelte delete mode 100644 svelte-full/src/components/editor/examples/full/extension.ts delete mode 100644 svelte-full/src/components/editor/examples/full/index.ts delete mode 100644 svelte-full/src/components/editor/sample/katex.ts delete mode 100644 svelte-full/src/components/editor/sample/sample-doc-full.ts delete mode 100644 svelte-full/src/components/editor/sample/sample-tag-data.ts delete mode 100644 svelte-full/src/components/editor/sample/sample-uploader.ts delete mode 100644 svelte-full/src/components/editor/sample/sample-user-data.ts delete mode 100644 svelte-full/src/components/editor/ui/block-handle/block-handle.svelte delete mode 100644 svelte-full/src/components/editor/ui/block-handle/index.ts delete mode 100644 svelte-full/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-full/src/components/editor/ui/button/index.ts delete mode 100644 svelte-full/src/components/editor/ui/code-block-view/code-block-view.svelte delete mode 100644 svelte-full/src/components/editor/ui/code-block-view/index.ts delete mode 100644 svelte-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte delete mode 100644 svelte-full/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 svelte-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-full/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-full/src/components/editor/ui/image-view/image-view.svelte delete mode 100644 svelte-full/src/components/editor/ui/image-view/index.ts delete mode 100644 svelte-full/src/components/editor/ui/inline-menu/index.ts delete mode 100644 svelte-full/src/components/editor/ui/inline-menu/inline-menu.svelte delete mode 100644 svelte-full/src/components/editor/ui/slash-menu/index.ts delete mode 100644 svelte-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte delete mode 100644 svelte-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte delete mode 100644 svelte-full/src/components/editor/ui/slash-menu/slash-menu.svelte delete mode 100644 svelte-full/src/components/editor/ui/table-handle/index.ts delete mode 100644 svelte-full/src/components/editor/ui/table-handle/table-handle.svelte delete mode 100644 svelte-full/src/components/editor/ui/tag-menu/index.ts delete mode 100644 svelte-full/src/components/editor/ui/tag-menu/tag-menu.svelte delete mode 100644 svelte-full/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-full/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-full/src/components/editor/ui/user-menu/index.ts delete mode 100644 svelte-full/src/components/editor/ui/user-menu/user-menu.svelte delete mode 100644 svelte-full/src/main.ts delete mode 100644 svelte-full/src/vite-env.d.ts delete mode 100644 svelte-full/svelte.config.js delete mode 100644 svelte-full/tsconfig.json delete mode 100644 svelte-full/tsconfig.node.json delete mode 100644 svelte-full/vite.config.ts delete mode 100644 svelte-gap-cursor/.gitignore delete mode 100644 svelte-gap-cursor/README.md delete mode 100644 svelte-gap-cursor/index.html delete mode 100644 svelte-gap-cursor/package.json delete mode 100644 svelte-gap-cursor/src/App.svelte delete mode 100644 svelte-gap-cursor/src/app.css delete mode 100644 svelte-gap-cursor/src/components/editor/examples/gap-cursor/editor.svelte delete mode 100644 svelte-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts delete mode 100644 svelte-gap-cursor/src/components/editor/examples/gap-cursor/index.ts delete mode 100644 svelte-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts delete mode 100644 svelte-gap-cursor/src/main.ts delete mode 100644 svelte-gap-cursor/src/vite-env.d.ts delete mode 100644 svelte-gap-cursor/svelte.config.js delete mode 100644 svelte-gap-cursor/tsconfig.json delete mode 100644 svelte-gap-cursor/tsconfig.node.json delete mode 100644 svelte-gap-cursor/vite.config.ts delete mode 100644 svelte-hard-break/.gitignore delete mode 100644 svelte-hard-break/README.md delete mode 100644 svelte-hard-break/index.html delete mode 100644 svelte-hard-break/package.json delete mode 100644 svelte-hard-break/src/App.svelte delete mode 100644 svelte-hard-break/src/app.css delete mode 100644 svelte-hard-break/src/components/editor/examples/hard-break/editor.svelte delete mode 100644 svelte-hard-break/src/components/editor/examples/hard-break/extension.ts delete mode 100644 svelte-hard-break/src/components/editor/examples/hard-break/index.ts delete mode 100644 svelte-hard-break/src/components/editor/examples/hard-break/toolbar.svelte delete mode 100644 svelte-hard-break/src/components/editor/sample/sample-doc-hard-break.ts delete mode 100644 svelte-hard-break/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-hard-break/src/components/editor/ui/button/index.ts delete mode 100644 svelte-hard-break/src/main.ts delete mode 100644 svelte-hard-break/src/vite-env.d.ts delete mode 100644 svelte-hard-break/svelte.config.js delete mode 100644 svelte-hard-break/tsconfig.json delete mode 100644 svelte-hard-break/tsconfig.node.json delete mode 100644 svelte-hard-break/vite.config.ts delete mode 100644 svelte-heading/.gitignore delete mode 100644 svelte-heading/README.md delete mode 100644 svelte-heading/index.html delete mode 100644 svelte-heading/package.json delete mode 100644 svelte-heading/src/App.svelte delete mode 100644 svelte-heading/src/app.css delete mode 100644 svelte-heading/src/components/editor/examples/heading/editor.svelte delete mode 100644 svelte-heading/src/components/editor/examples/heading/extension.ts delete mode 100644 svelte-heading/src/components/editor/examples/heading/index.ts delete mode 100644 svelte-heading/src/components/editor/sample/sample-doc-heading.ts delete mode 100644 svelte-heading/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-heading/src/components/editor/ui/button/index.ts delete mode 100644 svelte-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-heading/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-heading/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-heading/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-heading/src/main.ts delete mode 100644 svelte-heading/src/vite-env.d.ts delete mode 100644 svelte-heading/svelte.config.js delete mode 100644 svelte-heading/tsconfig.json delete mode 100644 svelte-heading/tsconfig.node.json delete mode 100644 svelte-heading/vite.config.ts delete mode 100644 svelte-highlight/.gitignore delete mode 100644 svelte-highlight/README.md delete mode 100644 svelte-highlight/index.html delete mode 100644 svelte-highlight/package.json delete mode 100644 svelte-highlight/src/App.svelte delete mode 100644 svelte-highlight/src/app.css delete mode 100644 svelte-highlight/src/components/editor/examples/highlight/editor.svelte delete mode 100644 svelte-highlight/src/components/editor/examples/highlight/extension.ts delete mode 100644 svelte-highlight/src/components/editor/examples/highlight/index.ts delete mode 100644 svelte-highlight/src/components/editor/examples/highlight/toolbar.svelte delete mode 100644 svelte-highlight/src/components/editor/sample/sample-doc-highlight.ts delete mode 100644 svelte-highlight/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-highlight/src/components/editor/ui/button/index.ts delete mode 100644 svelte-highlight/src/main.ts delete mode 100644 svelte-highlight/src/vite-env.d.ts delete mode 100644 svelte-highlight/svelte.config.js delete mode 100644 svelte-highlight/tsconfig.json delete mode 100644 svelte-highlight/tsconfig.node.json delete mode 100644 svelte-highlight/vite.config.ts delete mode 100644 svelte-horizontal-rule/.gitignore delete mode 100644 svelte-horizontal-rule/README.md delete mode 100644 svelte-horizontal-rule/index.html delete mode 100644 svelte-horizontal-rule/package.json delete mode 100644 svelte-horizontal-rule/src/App.svelte delete mode 100644 svelte-horizontal-rule/src/app.css delete mode 100644 svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.svelte delete mode 100644 svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts delete mode 100644 svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts delete mode 100644 svelte-horizontal-rule/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-horizontal-rule/src/components/editor/ui/button/index.ts delete mode 100644 svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-horizontal-rule/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-horizontal-rule/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-horizontal-rule/src/main.ts delete mode 100644 svelte-horizontal-rule/src/vite-env.d.ts delete mode 100644 svelte-horizontal-rule/svelte.config.js delete mode 100644 svelte-horizontal-rule/tsconfig.json delete mode 100644 svelte-horizontal-rule/tsconfig.node.json delete mode 100644 svelte-horizontal-rule/vite.config.ts delete mode 100644 svelte-image-view/.gitignore delete mode 100644 svelte-image-view/README.md delete mode 100644 svelte-image-view/index.html delete mode 100644 svelte-image-view/package.json delete mode 100644 svelte-image-view/src/App.svelte delete mode 100644 svelte-image-view/src/app.css delete mode 100644 svelte-image-view/src/components/editor/examples/image-view/editor.svelte delete mode 100644 svelte-image-view/src/components/editor/examples/image-view/extension.ts delete mode 100644 svelte-image-view/src/components/editor/examples/image-view/index.ts delete mode 100644 svelte-image-view/src/components/editor/sample/sample-doc-image.ts delete mode 100644 svelte-image-view/src/components/editor/sample/sample-uploader.ts delete mode 100644 svelte-image-view/src/components/editor/ui/image-view/image-view.svelte delete mode 100644 svelte-image-view/src/components/editor/ui/image-view/index.ts delete mode 100644 svelte-image-view/src/main.ts delete mode 100644 svelte-image-view/src/vite-env.d.ts delete mode 100644 svelte-image-view/svelte.config.js delete mode 100644 svelte-image-view/tsconfig.json delete mode 100644 svelte-image-view/tsconfig.node.json delete mode 100644 svelte-image-view/vite.config.ts delete mode 100644 svelte-inline-menu/.gitignore delete mode 100644 svelte-inline-menu/README.md delete mode 100644 svelte-inline-menu/index.html delete mode 100644 svelte-inline-menu/package.json delete mode 100644 svelte-inline-menu/src/App.svelte delete mode 100644 svelte-inline-menu/src/app.css delete mode 100644 svelte-inline-menu/src/components/editor/examples/inline-menu/editor.svelte delete mode 100644 svelte-inline-menu/src/components/editor/examples/inline-menu/extension.ts delete mode 100644 svelte-inline-menu/src/components/editor/examples/inline-menu/index.ts delete mode 100644 svelte-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts delete mode 100644 svelte-inline-menu/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-inline-menu/src/components/editor/ui/button/index.ts delete mode 100644 svelte-inline-menu/src/components/editor/ui/inline-menu/index.ts delete mode 100644 svelte-inline-menu/src/components/editor/ui/inline-menu/inline-menu.svelte delete mode 100644 svelte-inline-menu/src/main.ts delete mode 100644 svelte-inline-menu/src/vite-env.d.ts delete mode 100644 svelte-inline-menu/svelte.config.js delete mode 100644 svelte-inline-menu/tsconfig.json delete mode 100644 svelte-inline-menu/tsconfig.node.json delete mode 100644 svelte-inline-menu/vite.config.ts delete mode 100644 svelte-italic/.gitignore delete mode 100644 svelte-italic/README.md delete mode 100644 svelte-italic/index.html delete mode 100644 svelte-italic/package.json delete mode 100644 svelte-italic/src/App.svelte delete mode 100644 svelte-italic/src/app.css delete mode 100644 svelte-italic/src/components/editor/examples/italic/editor.svelte delete mode 100644 svelte-italic/src/components/editor/examples/italic/extension.ts delete mode 100644 svelte-italic/src/components/editor/examples/italic/index.ts delete mode 100644 svelte-italic/src/components/editor/sample/sample-doc-italic.ts delete mode 100644 svelte-italic/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-italic/src/components/editor/ui/button/index.ts delete mode 100644 svelte-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-italic/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-italic/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-italic/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-italic/src/main.ts delete mode 100644 svelte-italic/src/vite-env.d.ts delete mode 100644 svelte-italic/svelte.config.js delete mode 100644 svelte-italic/tsconfig.json delete mode 100644 svelte-italic/tsconfig.node.json delete mode 100644 svelte-italic/vite.config.ts delete mode 100644 svelte-katex/.gitignore delete mode 100644 svelte-katex/README.md delete mode 100644 svelte-katex/index.html delete mode 100644 svelte-katex/package.json delete mode 100644 svelte-katex/src/App.svelte delete mode 100644 svelte-katex/src/app.css delete mode 100644 svelte-katex/src/components/editor/examples/katex/editor.svelte delete mode 100644 svelte-katex/src/components/editor/examples/katex/extension.ts delete mode 100644 svelte-katex/src/components/editor/examples/katex/index.ts delete mode 100644 svelte-katex/src/components/editor/sample/katex.ts delete mode 100644 svelte-katex/src/components/editor/sample/sample-doc-tex.ts delete mode 100644 svelte-katex/src/main.ts delete mode 100644 svelte-katex/src/vite-env.d.ts delete mode 100644 svelte-katex/svelte.config.js delete mode 100644 svelte-katex/tsconfig.json delete mode 100644 svelte-katex/tsconfig.node.json delete mode 100644 svelte-katex/vite.config.ts delete mode 100644 svelte-keymap/.gitignore delete mode 100644 svelte-keymap/README.md delete mode 100644 svelte-keymap/index.html delete mode 100644 svelte-keymap/package.json delete mode 100644 svelte-keymap/src/App.svelte delete mode 100644 svelte-keymap/src/app.css delete mode 100644 svelte-keymap/src/components/editor/examples/keymap/editor.svelte delete mode 100644 svelte-keymap/src/components/editor/examples/keymap/extension.ts delete mode 100644 svelte-keymap/src/components/editor/examples/keymap/index.ts delete mode 100644 svelte-keymap/src/components/editor/examples/keymap/toolbar.svelte delete mode 100644 svelte-keymap/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-keymap/src/components/editor/ui/button/index.ts delete mode 100644 svelte-keymap/src/main.ts delete mode 100644 svelte-keymap/src/vite-env.d.ts delete mode 100644 svelte-keymap/svelte.config.js delete mode 100644 svelte-keymap/tsconfig.json delete mode 100644 svelte-keymap/tsconfig.node.json delete mode 100644 svelte-keymap/vite.config.ts delete mode 100644 svelte-link-mark-view/.gitignore delete mode 100644 svelte-link-mark-view/README.md delete mode 100644 svelte-link-mark-view/index.html delete mode 100644 svelte-link-mark-view/package.json delete mode 100644 svelte-link-mark-view/src/App.svelte delete mode 100644 svelte-link-mark-view/src/app.css delete mode 100644 svelte-link-mark-view/src/components/editor/examples/link-mark-view/editor.svelte delete mode 100644 svelte-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts delete mode 100644 svelte-link-mark-view/src/components/editor/examples/link-mark-view/index.ts delete mode 100644 svelte-link-mark-view/src/components/editor/examples/link-mark-view/link-view.svelte delete mode 100644 svelte-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts delete mode 100644 svelte-link-mark-view/src/main.ts delete mode 100644 svelte-link-mark-view/src/vite-env.d.ts delete mode 100644 svelte-link-mark-view/svelte.config.js delete mode 100644 svelte-link-mark-view/tsconfig.json delete mode 100644 svelte-link-mark-view/tsconfig.node.json delete mode 100644 svelte-link-mark-view/vite.config.ts delete mode 100644 svelte-link/.gitignore delete mode 100644 svelte-link/README.md delete mode 100644 svelte-link/index.html delete mode 100644 svelte-link/package.json delete mode 100644 svelte-link/src/App.svelte delete mode 100644 svelte-link/src/app.css delete mode 100644 svelte-link/src/components/editor/examples/link/editor.svelte delete mode 100644 svelte-link/src/components/editor/examples/link/extension.ts delete mode 100644 svelte-link/src/components/editor/examples/link/index.ts delete mode 100644 svelte-link/src/components/editor/sample/sample-doc-link.ts delete mode 100644 svelte-link/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-link/src/components/editor/ui/button/index.ts delete mode 100644 svelte-link/src/components/editor/ui/inline-menu/index.ts delete mode 100644 svelte-link/src/components/editor/ui/inline-menu/inline-menu.svelte delete mode 100644 svelte-link/src/main.ts delete mode 100644 svelte-link/src/vite-env.d.ts delete mode 100644 svelte-link/svelte.config.js delete mode 100644 svelte-link/tsconfig.json delete mode 100644 svelte-link/tsconfig.node.json delete mode 100644 svelte-link/vite.config.ts delete mode 100644 svelte-list-custom-checkbox/.gitignore delete mode 100644 svelte-list-custom-checkbox/README.md delete mode 100644 svelte-list-custom-checkbox/index.html delete mode 100644 svelte-list-custom-checkbox/package.json delete mode 100644 svelte-list-custom-checkbox/src/App.svelte delete mode 100644 svelte-list-custom-checkbox/src/app.css delete mode 100644 svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css delete mode 100644 svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.svelte delete mode 100644 svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts delete mode 100644 svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts delete mode 100644 svelte-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts delete mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/button/index.ts delete mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-list-custom-checkbox/src/main.ts delete mode 100644 svelte-list-custom-checkbox/src/vite-env.d.ts delete mode 100644 svelte-list-custom-checkbox/svelte.config.js delete mode 100644 svelte-list-custom-checkbox/tsconfig.json delete mode 100644 svelte-list-custom-checkbox/tsconfig.node.json delete mode 100644 svelte-list-custom-checkbox/vite.config.ts delete mode 100644 svelte-list/.gitignore delete mode 100644 svelte-list/README.md delete mode 100644 svelte-list/index.html delete mode 100644 svelte-list/package.json delete mode 100644 svelte-list/src/App.svelte delete mode 100644 svelte-list/src/app.css delete mode 100644 svelte-list/src/components/editor/examples/list/editor.svelte delete mode 100644 svelte-list/src/components/editor/examples/list/extension.ts delete mode 100644 svelte-list/src/components/editor/examples/list/index.ts delete mode 100644 svelte-list/src/components/editor/sample/sample-doc-list.ts delete mode 100644 svelte-list/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-list/src/components/editor/ui/button/index.ts delete mode 100644 svelte-list/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-list/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-list/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-list/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-list/src/main.ts delete mode 100644 svelte-list/src/vite-env.d.ts delete mode 100644 svelte-list/svelte.config.js delete mode 100644 svelte-list/tsconfig.json delete mode 100644 svelte-list/tsconfig.node.json delete mode 100644 svelte-list/vite.config.ts delete mode 100644 svelte-loro/.gitignore delete mode 100644 svelte-loro/README.md delete mode 100644 svelte-loro/index.html delete mode 100644 svelte-loro/package.json delete mode 100644 svelte-loro/src/App.svelte delete mode 100644 svelte-loro/src/app.css delete mode 100644 svelte-loro/src/components/editor/examples/loro/editor-component.svelte delete mode 100644 svelte-loro/src/components/editor/examples/loro/editor.svelte delete mode 100644 svelte-loro/src/components/editor/examples/loro/extension.ts delete mode 100644 svelte-loro/src/components/editor/examples/loro/index.ts delete mode 100644 svelte-loro/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-loro/src/components/editor/ui/button/index.ts delete mode 100644 svelte-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-loro/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-loro/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-loro/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-loro/src/main.ts delete mode 100644 svelte-loro/src/vite-env.d.ts delete mode 100644 svelte-loro/svelte.config.js delete mode 100644 svelte-loro/tsconfig.json delete mode 100644 svelte-loro/tsconfig.node.json delete mode 100644 svelte-loro/vite.config.ts delete mode 100644 svelte-mark-rule/.gitignore delete mode 100644 svelte-mark-rule/README.md delete mode 100644 svelte-mark-rule/index.html delete mode 100644 svelte-mark-rule/package.json delete mode 100644 svelte-mark-rule/src/App.svelte delete mode 100644 svelte-mark-rule/src/app.css delete mode 100644 svelte-mark-rule/src/components/editor/examples/mark-rule/editor.svelte delete mode 100644 svelte-mark-rule/src/components/editor/examples/mark-rule/extension.ts delete mode 100644 svelte-mark-rule/src/components/editor/examples/mark-rule/index.ts delete mode 100644 svelte-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts delete mode 100644 svelte-mark-rule/src/main.ts delete mode 100644 svelte-mark-rule/src/vite-env.d.ts delete mode 100644 svelte-mark-rule/svelte.config.js delete mode 100644 svelte-mark-rule/tsconfig.json delete mode 100644 svelte-mark-rule/tsconfig.node.json delete mode 100644 svelte-mark-rule/vite.config.ts delete mode 100644 svelte-minimal/.gitignore delete mode 100644 svelte-minimal/README.md delete mode 100644 svelte-minimal/index.html delete mode 100644 svelte-minimal/package.json delete mode 100644 svelte-minimal/src/App.svelte delete mode 100644 svelte-minimal/src/app.css delete mode 100644 svelte-minimal/src/components/editor/examples/minimal/editor.svelte delete mode 100644 svelte-minimal/src/components/editor/examples/minimal/index.ts delete mode 100644 svelte-minimal/src/main.ts delete mode 100644 svelte-minimal/src/vite-env.d.ts delete mode 100644 svelte-minimal/svelte.config.js delete mode 100644 svelte-minimal/tsconfig.json delete mode 100644 svelte-minimal/tsconfig.node.json delete mode 100644 svelte-minimal/vite.config.ts delete mode 100644 svelte-page/.gitignore delete mode 100644 svelte-page/README.md delete mode 100644 svelte-page/index.html delete mode 100644 svelte-page/package.json delete mode 100644 svelte-page/src/App.svelte delete mode 100644 svelte-page/src/app.css delete mode 100644 svelte-page/src/components/editor/examples/page/editor.svelte delete mode 100644 svelte-page/src/components/editor/examples/page/extension.ts delete mode 100644 svelte-page/src/components/editor/examples/page/index.ts delete mode 100644 svelte-page/src/components/editor/examples/page/paper-controller.svelte delete mode 100644 svelte-page/src/components/editor/examples/page/zoom.css delete mode 100644 svelte-page/src/components/editor/sample/sample-doc-page.ts delete mode 100644 svelte-page/src/main.ts delete mode 100644 svelte-page/src/vite-env.d.ts delete mode 100644 svelte-page/svelte.config.js delete mode 100644 svelte-page/tsconfig.json delete mode 100644 svelte-page/tsconfig.node.json delete mode 100644 svelte-page/vite.config.ts delete mode 100644 svelte-placeholder/.gitignore delete mode 100644 svelte-placeholder/README.md delete mode 100644 svelte-placeholder/index.html delete mode 100644 svelte-placeholder/package.json delete mode 100644 svelte-placeholder/src/App.svelte delete mode 100644 svelte-placeholder/src/app.css delete mode 100644 svelte-placeholder/src/components/editor/examples/placeholder/editor.svelte delete mode 100644 svelte-placeholder/src/components/editor/examples/placeholder/extension.ts delete mode 100644 svelte-placeholder/src/components/editor/examples/placeholder/index.ts delete mode 100644 svelte-placeholder/src/main.ts delete mode 100644 svelte-placeholder/src/vite-env.d.ts delete mode 100644 svelte-placeholder/svelte.config.js delete mode 100644 svelte-placeholder/tsconfig.json delete mode 100644 svelte-placeholder/tsconfig.node.json delete mode 100644 svelte-placeholder/vite.config.ts delete mode 100644 svelte-readonly/.gitignore delete mode 100644 svelte-readonly/README.md delete mode 100644 svelte-readonly/index.html delete mode 100644 svelte-readonly/package.json delete mode 100644 svelte-readonly/src/App.svelte delete mode 100644 svelte-readonly/src/app.css delete mode 100644 svelte-readonly/src/components/editor/examples/readonly/editor.svelte delete mode 100644 svelte-readonly/src/components/editor/examples/readonly/extension.ts delete mode 100644 svelte-readonly/src/components/editor/examples/readonly/index.ts delete mode 100644 svelte-readonly/src/components/editor/examples/readonly/toolbar.svelte delete mode 100644 svelte-readonly/src/components/editor/sample/sample-doc-readonly.ts delete mode 100644 svelte-readonly/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-readonly/src/components/editor/ui/button/index.ts delete mode 100644 svelte-readonly/src/main.ts delete mode 100644 svelte-readonly/src/vite-env.d.ts delete mode 100644 svelte-readonly/svelte.config.js delete mode 100644 svelte-readonly/tsconfig.json delete mode 100644 svelte-readonly/tsconfig.node.json delete mode 100644 svelte-readonly/vite.config.ts delete mode 100644 svelte-rtl/.gitignore delete mode 100644 svelte-rtl/README.md delete mode 100644 svelte-rtl/index.html delete mode 100644 svelte-rtl/package.json delete mode 100644 svelte-rtl/src/App.svelte delete mode 100644 svelte-rtl/src/app.css delete mode 100644 svelte-rtl/src/components/editor/examples/rtl/editor.svelte delete mode 100644 svelte-rtl/src/components/editor/examples/rtl/index.ts delete mode 100644 svelte-rtl/src/components/editor/sample/sample-doc-rtl.ts delete mode 100644 svelte-rtl/src/components/editor/sample/sample-uploader.ts delete mode 100644 svelte-rtl/src/components/editor/ui/block-handle/block-handle.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/block-handle/index.ts delete mode 100644 svelte-rtl/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/button/index.ts delete mode 100644 svelte-rtl/src/components/editor/ui/drop-indicator/drop-indicator.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 svelte-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-rtl/src/components/editor/ui/inline-menu/index.ts delete mode 100644 svelte-rtl/src/components/editor/ui/inline-menu/inline-menu.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/slash-menu/index.ts delete mode 100644 svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-item.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/slash-menu/slash-menu.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/table-handle/index.ts delete mode 100644 svelte-rtl/src/components/editor/ui/table-handle/table-handle.svelte delete mode 100644 svelte-rtl/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-rtl/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-rtl/src/main.ts delete mode 100644 svelte-rtl/src/vite-env.d.ts delete mode 100644 svelte-rtl/svelte.config.js delete mode 100644 svelte-rtl/tsconfig.json delete mode 100644 svelte-rtl/tsconfig.node.json delete mode 100644 svelte-rtl/vite.config.ts delete mode 100644 svelte-save-html/.gitignore delete mode 100644 svelte-save-html/README.md delete mode 100644 svelte-save-html/index.html delete mode 100644 svelte-save-html/package.json delete mode 100644 svelte-save-html/src/App.svelte delete mode 100644 svelte-save-html/src/app.css delete mode 100644 svelte-save-html/src/components/editor/examples/save-html/editor.svelte delete mode 100644 svelte-save-html/src/components/editor/examples/save-html/index.ts delete mode 100644 svelte-save-html/src/main.ts delete mode 100644 svelte-save-html/src/vite-env.d.ts delete mode 100644 svelte-save-html/svelte.config.js delete mode 100644 svelte-save-html/tsconfig.json delete mode 100644 svelte-save-html/tsconfig.node.json delete mode 100644 svelte-save-html/vite.config.ts delete mode 100644 svelte-save-json/.gitignore delete mode 100644 svelte-save-json/README.md delete mode 100644 svelte-save-json/index.html delete mode 100644 svelte-save-json/package.json delete mode 100644 svelte-save-json/src/App.svelte delete mode 100644 svelte-save-json/src/app.css delete mode 100644 svelte-save-json/src/components/editor/examples/save-json/editor.svelte delete mode 100644 svelte-save-json/src/components/editor/examples/save-json/index.ts delete mode 100644 svelte-save-json/src/main.ts delete mode 100644 svelte-save-json/src/vite-env.d.ts delete mode 100644 svelte-save-json/svelte.config.js delete mode 100644 svelte-save-json/tsconfig.json delete mode 100644 svelte-save-json/tsconfig.node.json delete mode 100644 svelte-save-json/vite.config.ts delete mode 100644 svelte-save-markdown/.gitignore delete mode 100644 svelte-save-markdown/README.md delete mode 100644 svelte-save-markdown/index.html delete mode 100644 svelte-save-markdown/package.json delete mode 100644 svelte-save-markdown/src/App.svelte delete mode 100644 svelte-save-markdown/src/app.css delete mode 100644 svelte-save-markdown/src/components/editor/examples/save-markdown/editor.svelte delete mode 100644 svelte-save-markdown/src/components/editor/examples/save-markdown/index.ts delete mode 100644 svelte-save-markdown/src/components/editor/examples/save-markdown/markdown.ts delete mode 100644 svelte-save-markdown/src/main.ts delete mode 100644 svelte-save-markdown/src/vite-env.d.ts delete mode 100644 svelte-save-markdown/svelte.config.js delete mode 100644 svelte-save-markdown/tsconfig.json delete mode 100644 svelte-save-markdown/tsconfig.node.json delete mode 100644 svelte-save-markdown/vite.config.ts delete mode 100644 svelte-search/.gitignore delete mode 100644 svelte-search/README.md delete mode 100644 svelte-search/index.html delete mode 100644 svelte-search/package.json delete mode 100644 svelte-search/src/App.svelte delete mode 100644 svelte-search/src/app.css delete mode 100644 svelte-search/src/components/editor/examples/search/editor.svelte delete mode 100644 svelte-search/src/components/editor/examples/search/extension.ts delete mode 100644 svelte-search/src/components/editor/examples/search/index.ts delete mode 100644 svelte-search/src/components/editor/sample/sample-doc-search.ts delete mode 100644 svelte-search/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-search/src/components/editor/ui/button/index.ts delete mode 100644 svelte-search/src/components/editor/ui/search/index.ts delete mode 100644 svelte-search/src/components/editor/ui/search/search.svelte delete mode 100644 svelte-search/src/main.ts delete mode 100644 svelte-search/src/vite-env.d.ts delete mode 100644 svelte-search/svelte.config.js delete mode 100644 svelte-search/tsconfig.json delete mode 100644 svelte-search/tsconfig.node.json delete mode 100644 svelte-search/vite.config.ts delete mode 100644 svelte-slash-menu/.gitignore delete mode 100644 svelte-slash-menu/README.md delete mode 100644 svelte-slash-menu/index.html delete mode 100644 svelte-slash-menu/package.json delete mode 100644 svelte-slash-menu/src/App.svelte delete mode 100644 svelte-slash-menu/src/app.css delete mode 100644 svelte-slash-menu/src/components/editor/examples/slash-menu/editor.svelte delete mode 100644 svelte-slash-menu/src/components/editor/examples/slash-menu/extension.ts delete mode 100644 svelte-slash-menu/src/components/editor/examples/slash-menu/index.ts delete mode 100644 svelte-slash-menu/src/components/editor/ui/slash-menu/index.ts delete mode 100644 svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.svelte delete mode 100644 svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.svelte delete mode 100644 svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu.svelte delete mode 100644 svelte-slash-menu/src/main.ts delete mode 100644 svelte-slash-menu/src/vite-env.d.ts delete mode 100644 svelte-slash-menu/svelte.config.js delete mode 100644 svelte-slash-menu/tsconfig.json delete mode 100644 svelte-slash-menu/tsconfig.node.json delete mode 100644 svelte-slash-menu/vite.config.ts delete mode 100644 svelte-strike/.gitignore delete mode 100644 svelte-strike/README.md delete mode 100644 svelte-strike/index.html delete mode 100644 svelte-strike/package.json delete mode 100644 svelte-strike/src/App.svelte delete mode 100644 svelte-strike/src/app.css delete mode 100644 svelte-strike/src/components/editor/examples/strike/editor.svelte delete mode 100644 svelte-strike/src/components/editor/examples/strike/extension.ts delete mode 100644 svelte-strike/src/components/editor/examples/strike/index.ts delete mode 100644 svelte-strike/src/components/editor/examples/strike/toolbar.svelte delete mode 100644 svelte-strike/src/components/editor/sample/sample-doc-strike.ts delete mode 100644 svelte-strike/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-strike/src/components/editor/ui/button/index.ts delete mode 100644 svelte-strike/src/main.ts delete mode 100644 svelte-strike/src/vite-env.d.ts delete mode 100644 svelte-strike/svelte.config.js delete mode 100644 svelte-strike/tsconfig.json delete mode 100644 svelte-strike/tsconfig.node.json delete mode 100644 svelte-strike/vite.config.ts delete mode 100644 svelte-sub-sup/.gitignore delete mode 100644 svelte-sub-sup/README.md delete mode 100644 svelte-sub-sup/index.html delete mode 100644 svelte-sub-sup/package.json delete mode 100644 svelte-sub-sup/src/App.svelte delete mode 100644 svelte-sub-sup/src/app.css delete mode 100644 svelte-sub-sup/src/components/editor/examples/sub-sup/editor.svelte delete mode 100644 svelte-sub-sup/src/components/editor/examples/sub-sup/extension.ts delete mode 100644 svelte-sub-sup/src/components/editor/examples/sub-sup/index.ts delete mode 100644 svelte-sub-sup/src/components/editor/examples/sub-sup/toolbar.svelte delete mode 100644 svelte-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts delete mode 100644 svelte-sub-sup/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-sub-sup/src/components/editor/ui/button/index.ts delete mode 100644 svelte-sub-sup/src/main.ts delete mode 100644 svelte-sub-sup/src/vite-env.d.ts delete mode 100644 svelte-sub-sup/svelte.config.js delete mode 100644 svelte-sub-sup/tsconfig.json delete mode 100644 svelte-sub-sup/tsconfig.node.json delete mode 100644 svelte-sub-sup/vite.config.ts delete mode 100644 svelte-table/.gitignore delete mode 100644 svelte-table/README.md delete mode 100644 svelte-table/index.html delete mode 100644 svelte-table/package.json delete mode 100644 svelte-table/src/App.svelte delete mode 100644 svelte-table/src/app.css delete mode 100644 svelte-table/src/components/editor/examples/table/editor.svelte delete mode 100644 svelte-table/src/components/editor/examples/table/extension.ts delete mode 100644 svelte-table/src/components/editor/examples/table/index.ts delete mode 100644 svelte-table/src/components/editor/sample/sample-doc-table.ts delete mode 100644 svelte-table/src/components/editor/ui/table-handle/index.ts delete mode 100644 svelte-table/src/components/editor/ui/table-handle/table-handle.svelte delete mode 100644 svelte-table/src/main.ts delete mode 100644 svelte-table/src/vite-env.d.ts delete mode 100644 svelte-table/svelte.config.js delete mode 100644 svelte-table/tsconfig.json delete mode 100644 svelte-table/tsconfig.node.json delete mode 100644 svelte-table/vite.config.ts delete mode 100644 svelte-text-align/.gitignore delete mode 100644 svelte-text-align/README.md delete mode 100644 svelte-text-align/index.html delete mode 100644 svelte-text-align/package.json delete mode 100644 svelte-text-align/src/App.svelte delete mode 100644 svelte-text-align/src/app.css delete mode 100644 svelte-text-align/src/components/editor/examples/text-align/editor.svelte delete mode 100644 svelte-text-align/src/components/editor/examples/text-align/extension.ts delete mode 100644 svelte-text-align/src/components/editor/examples/text-align/index.ts delete mode 100644 svelte-text-align/src/components/editor/examples/text-align/toolbar.svelte delete mode 100644 svelte-text-align/src/components/editor/sample/sample-doc-text-align.ts delete mode 100644 svelte-text-align/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-text-align/src/components/editor/ui/button/index.ts delete mode 100644 svelte-text-align/src/main.ts delete mode 100644 svelte-text-align/src/vite-env.d.ts delete mode 100644 svelte-text-align/svelte.config.js delete mode 100644 svelte-text-align/tsconfig.json delete mode 100644 svelte-text-align/tsconfig.node.json delete mode 100644 svelte-text-align/vite.config.ts delete mode 100644 svelte-text-color/.gitignore delete mode 100644 svelte-text-color/README.md delete mode 100644 svelte-text-color/index.html delete mode 100644 svelte-text-color/package.json delete mode 100644 svelte-text-color/src/App.svelte delete mode 100644 svelte-text-color/src/app.css delete mode 100644 svelte-text-color/src/components/editor/examples/text-color/editor.svelte delete mode 100644 svelte-text-color/src/components/editor/examples/text-color/extension.ts delete mode 100644 svelte-text-color/src/components/editor/examples/text-color/index.ts delete mode 100644 svelte-text-color/src/components/editor/examples/text-color/inline-menu.svelte delete mode 100644 svelte-text-color/src/components/editor/sample/sample-doc-text-color.ts delete mode 100644 svelte-text-color/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-text-color/src/components/editor/ui/button/index.ts delete mode 100644 svelte-text-color/src/main.ts delete mode 100644 svelte-text-color/src/vite-env.d.ts delete mode 100644 svelte-text-color/svelte.config.js delete mode 100644 svelte-text-color/tsconfig.json delete mode 100644 svelte-text-color/tsconfig.node.json delete mode 100644 svelte-text-color/vite.config.ts delete mode 100644 svelte-toolbar/.gitignore delete mode 100644 svelte-toolbar/README.md delete mode 100644 svelte-toolbar/index.html delete mode 100644 svelte-toolbar/package.json delete mode 100644 svelte-toolbar/src/App.svelte delete mode 100644 svelte-toolbar/src/app.css delete mode 100644 svelte-toolbar/src/components/editor/examples/toolbar/editor.svelte delete mode 100644 svelte-toolbar/src/components/editor/examples/toolbar/extension.ts delete mode 100644 svelte-toolbar/src/components/editor/examples/toolbar/index.ts delete mode 100644 svelte-toolbar/src/components/editor/sample/sample-uploader.ts delete mode 100644 svelte-toolbar/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-toolbar/src/components/editor/ui/button/index.ts delete mode 100644 svelte-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-toolbar/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-toolbar/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-toolbar/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-toolbar/src/main.ts delete mode 100644 svelte-toolbar/src/vite-env.d.ts delete mode 100644 svelte-toolbar/svelte.config.js delete mode 100644 svelte-toolbar/tsconfig.json delete mode 100644 svelte-toolbar/tsconfig.node.json delete mode 100644 svelte-toolbar/vite.config.ts delete mode 100644 svelte-typography/.gitignore delete mode 100644 svelte-typography/README.md delete mode 100644 svelte-typography/index.html delete mode 100644 svelte-typography/package.json delete mode 100644 svelte-typography/src/App.svelte delete mode 100644 svelte-typography/src/app.css delete mode 100644 svelte-typography/src/components/editor/examples/typography/editor.svelte delete mode 100644 svelte-typography/src/components/editor/examples/typography/extension.ts delete mode 100644 svelte-typography/src/components/editor/examples/typography/index.ts delete mode 100644 svelte-typography/src/components/editor/sample/katex.ts delete mode 100644 svelte-typography/src/components/editor/sample/sample-doc-typography.ts delete mode 100644 svelte-typography/src/components/editor/ui/block-handle/block-handle.svelte delete mode 100644 svelte-typography/src/components/editor/ui/block-handle/index.ts delete mode 100644 svelte-typography/src/components/editor/ui/drop-indicator/drop-indicator.svelte delete mode 100644 svelte-typography/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 svelte-typography/src/main.ts delete mode 100644 svelte-typography/src/vite-env.d.ts delete mode 100644 svelte-typography/svelte.config.js delete mode 100644 svelte-typography/tsconfig.json delete mode 100644 svelte-typography/tsconfig.node.json delete mode 100644 svelte-typography/vite.config.ts delete mode 100644 svelte-underline/.gitignore delete mode 100644 svelte-underline/README.md delete mode 100644 svelte-underline/index.html delete mode 100644 svelte-underline/package.json delete mode 100644 svelte-underline/src/App.svelte delete mode 100644 svelte-underline/src/app.css delete mode 100644 svelte-underline/src/components/editor/examples/underline/editor.svelte delete mode 100644 svelte-underline/src/components/editor/examples/underline/extension.ts delete mode 100644 svelte-underline/src/components/editor/examples/underline/index.ts delete mode 100644 svelte-underline/src/components/editor/sample/sample-doc-underline.ts delete mode 100644 svelte-underline/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-underline/src/components/editor/ui/button/index.ts delete mode 100644 svelte-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-underline/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-underline/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-underline/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-underline/src/main.ts delete mode 100644 svelte-underline/src/vite-env.d.ts delete mode 100644 svelte-underline/svelte.config.js delete mode 100644 svelte-underline/tsconfig.json delete mode 100644 svelte-underline/tsconfig.node.json delete mode 100644 svelte-underline/vite.config.ts delete mode 100644 svelte-unmount/.gitignore delete mode 100644 svelte-unmount/README.md delete mode 100644 svelte-unmount/index.html delete mode 100644 svelte-unmount/package.json delete mode 100644 svelte-unmount/src/App.svelte delete mode 100644 svelte-unmount/src/app.css delete mode 100644 svelte-unmount/src/components/editor/examples/unmount/editor-component.svelte delete mode 100644 svelte-unmount/src/components/editor/examples/unmount/editor.svelte delete mode 100644 svelte-unmount/src/components/editor/examples/unmount/extension-component.svelte delete mode 100644 svelte-unmount/src/components/editor/examples/unmount/index.ts delete mode 100644 svelte-unmount/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-unmount/src/components/editor/ui/button/index.ts delete mode 100644 svelte-unmount/src/components/editor/ui/inline-menu/index.ts delete mode 100644 svelte-unmount/src/components/editor/ui/inline-menu/inline-menu.svelte delete mode 100644 svelte-unmount/src/main.ts delete mode 100644 svelte-unmount/src/vite-env.d.ts delete mode 100644 svelte-unmount/svelte.config.js delete mode 100644 svelte-unmount/tsconfig.json delete mode 100644 svelte-unmount/tsconfig.node.json delete mode 100644 svelte-unmount/vite.config.ts delete mode 100644 svelte-user-menu-dynamic/.gitignore delete mode 100644 svelte-user-menu-dynamic/README.md delete mode 100644 svelte-user-menu-dynamic/index.html delete mode 100644 svelte-user-menu-dynamic/package.json delete mode 100644 svelte-user-menu-dynamic/src/App.svelte delete mode 100644 svelte-user-menu-dynamic/src/app.css delete mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.svelte delete mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts delete mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts delete mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.svelte.ts delete mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.svelte delete mode 100644 svelte-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts delete mode 100644 svelte-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts delete mode 100644 svelte-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts delete mode 100644 svelte-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.svelte delete mode 100644 svelte-user-menu-dynamic/src/main.ts delete mode 100644 svelte-user-menu-dynamic/src/vite-env.d.ts delete mode 100644 svelte-user-menu-dynamic/svelte.config.js delete mode 100644 svelte-user-menu-dynamic/tsconfig.json delete mode 100644 svelte-user-menu-dynamic/tsconfig.node.json delete mode 100644 svelte-user-menu-dynamic/vite.config.ts delete mode 100644 svelte-user-menu/.gitignore delete mode 100644 svelte-user-menu/README.md delete mode 100644 svelte-user-menu/index.html delete mode 100644 svelte-user-menu/package.json delete mode 100644 svelte-user-menu/src/App.svelte delete mode 100644 svelte-user-menu/src/app.css delete mode 100644 svelte-user-menu/src/components/editor/examples/user-menu/editor.svelte delete mode 100644 svelte-user-menu/src/components/editor/examples/user-menu/extension.ts delete mode 100644 svelte-user-menu/src/components/editor/examples/user-menu/index.ts delete mode 100644 svelte-user-menu/src/components/editor/sample/sample-tag-data.ts delete mode 100644 svelte-user-menu/src/components/editor/sample/sample-user-data.ts delete mode 100644 svelte-user-menu/src/components/editor/ui/tag-menu/index.ts delete mode 100644 svelte-user-menu/src/components/editor/ui/tag-menu/tag-menu.svelte delete mode 100644 svelte-user-menu/src/components/editor/ui/user-menu/index.ts delete mode 100644 svelte-user-menu/src/components/editor/ui/user-menu/user-menu.svelte delete mode 100644 svelte-user-menu/src/main.ts delete mode 100644 svelte-user-menu/src/vite-env.d.ts delete mode 100644 svelte-user-menu/svelte.config.js delete mode 100644 svelte-user-menu/tsconfig.json delete mode 100644 svelte-user-menu/tsconfig.node.json delete mode 100644 svelte-user-menu/vite.config.ts delete mode 100644 svelte-word-counter/.gitignore delete mode 100644 svelte-word-counter/README.md delete mode 100644 svelte-word-counter/index.html delete mode 100644 svelte-word-counter/package.json delete mode 100644 svelte-word-counter/src/App.svelte delete mode 100644 svelte-word-counter/src/app.css delete mode 100644 svelte-word-counter/src/components/editor/examples/word-counter/editor.svelte delete mode 100644 svelte-word-counter/src/components/editor/examples/word-counter/extension.ts delete mode 100644 svelte-word-counter/src/components/editor/examples/word-counter/index.ts delete mode 100644 svelte-word-counter/src/components/editor/sample/sample-doc-word-counter.ts delete mode 100644 svelte-word-counter/src/components/editor/ui/word-counter/index.ts delete mode 100644 svelte-word-counter/src/components/editor/ui/word-counter/word-counter.svelte delete mode 100644 svelte-word-counter/src/main.ts delete mode 100644 svelte-word-counter/src/vite-env.d.ts delete mode 100644 svelte-word-counter/svelte.config.js delete mode 100644 svelte-word-counter/tsconfig.json delete mode 100644 svelte-word-counter/tsconfig.node.json delete mode 100644 svelte-word-counter/vite.config.ts delete mode 100644 svelte-yjs/.gitignore delete mode 100644 svelte-yjs/README.md delete mode 100644 svelte-yjs/index.html delete mode 100644 svelte-yjs/package.json delete mode 100644 svelte-yjs/src/App.svelte delete mode 100644 svelte-yjs/src/app.css delete mode 100644 svelte-yjs/src/components/editor/examples/yjs/editor-component.svelte delete mode 100644 svelte-yjs/src/components/editor/examples/yjs/editor.svelte delete mode 100644 svelte-yjs/src/components/editor/examples/yjs/extension.ts delete mode 100644 svelte-yjs/src/components/editor/examples/yjs/index.ts delete mode 100644 svelte-yjs/src/components/editor/ui/button/button.svelte delete mode 100644 svelte-yjs/src/components/editor/ui/button/index.ts delete mode 100644 svelte-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 svelte-yjs/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 svelte-yjs/src/components/editor/ui/toolbar/index.ts delete mode 100644 svelte-yjs/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 svelte-yjs/src/main.ts delete mode 100644 svelte-yjs/src/vite-env.d.ts delete mode 100644 svelte-yjs/svelte.config.js delete mode 100644 svelte-yjs/tsconfig.json delete mode 100644 svelte-yjs/tsconfig.node.json delete mode 100644 svelte-yjs/vite.config.ts delete mode 100644 sveltekit-full/.gitignore delete mode 100644 sveltekit-full/README.md delete mode 100644 sveltekit-full/package.json delete mode 100644 sveltekit-full/src/app.css delete mode 100644 sveltekit-full/src/app.d.ts delete mode 100644 sveltekit-full/src/app.html delete mode 100644 sveltekit-full/src/components/editor/examples/full/editor.svelte delete mode 100644 sveltekit-full/src/components/editor/examples/full/extension.ts delete mode 100644 sveltekit-full/src/components/editor/examples/full/index.ts delete mode 100644 sveltekit-full/src/components/editor/sample/katex.ts delete mode 100644 sveltekit-full/src/components/editor/sample/sample-doc-full.ts delete mode 100644 sveltekit-full/src/components/editor/sample/sample-tag-data.ts delete mode 100644 sveltekit-full/src/components/editor/sample/sample-uploader.ts delete mode 100644 sveltekit-full/src/components/editor/sample/sample-user-data.ts delete mode 100644 sveltekit-full/src/components/editor/ui/block-handle/block-handle.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/block-handle/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/button/button.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/button/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/code-block-view/code-block-view.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/code-block-view/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/image-view/image-view.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/image-view/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/inline-menu/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/inline-menu/inline-menu.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/slash-menu/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/slash-menu/slash-menu.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/table-handle/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/table-handle/table-handle.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/tag-menu/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/tag-menu/tag-menu.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/toolbar/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/toolbar/toolbar.svelte delete mode 100644 sveltekit-full/src/components/editor/ui/user-menu/index.ts delete mode 100644 sveltekit-full/src/components/editor/ui/user-menu/user-menu.svelte delete mode 100644 sveltekit-full/src/lib/App.svelte delete mode 100644 sveltekit-full/src/lib/client-only-editor.svelte delete mode 100644 sveltekit-full/src/lib/editor.svelte delete mode 100644 sveltekit-full/src/routes/+layout.svelte delete mode 100644 sveltekit-full/src/routes/+page.svelte delete mode 100644 sveltekit-full/static/favicon.png delete mode 100644 sveltekit-full/svelte.config.js delete mode 100644 sveltekit-full/tsconfig.json delete mode 100644 sveltekit-full/vite.config.ts delete mode 100644 vanilla-minimal/.gitignore delete mode 100644 vanilla-minimal/README.md delete mode 100644 vanilla-minimal/index.html delete mode 100644 vanilla-minimal/package.json delete mode 100644 vanilla-minimal/src/app.css delete mode 100644 vanilla-minimal/src/components/editor/examples/minimal/editor.ts delete mode 100644 vanilla-minimal/src/components/editor/examples/minimal/index.ts delete mode 100644 vanilla-minimal/src/editor.ts delete mode 100644 vanilla-minimal/src/main.ts delete mode 100644 vanilla-minimal/tsconfig.json delete mode 100644 vanilla-minimal/vite.config.ts delete mode 100644 vanilla-slash-menu/.gitignore delete mode 100644 vanilla-slash-menu/README.md delete mode 100644 vanilla-slash-menu/index.html delete mode 100644 vanilla-slash-menu/package.json delete mode 100644 vanilla-slash-menu/src/app.css delete mode 100644 vanilla-slash-menu/src/components/editor/examples/slash-menu/editor.ts delete mode 100644 vanilla-slash-menu/src/components/editor/examples/slash-menu/extension.ts delete mode 100644 vanilla-slash-menu/src/components/editor/examples/slash-menu/index.ts delete mode 100644 vanilla-slash-menu/src/components/editor/ui/slash-menu/index.ts delete mode 100644 vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts delete mode 100644 vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts delete mode 100644 vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts delete mode 100644 vanilla-slash-menu/src/editor.ts delete mode 100644 vanilla-slash-menu/src/main.ts delete mode 100644 vanilla-slash-menu/tsconfig.json delete mode 100644 vanilla-slash-menu/vite.config.ts delete mode 100644 vue-block-handle/.gitignore delete mode 100644 vue-block-handle/README.md delete mode 100644 vue-block-handle/index.html delete mode 100644 vue-block-handle/package.json delete mode 100644 vue-block-handle/src/App.vue delete mode 100644 vue-block-handle/src/app.css delete mode 100644 vue-block-handle/src/components/editor/examples/block-handle/editor.vue delete mode 100644 vue-block-handle/src/components/editor/examples/block-handle/extension.ts delete mode 100644 vue-block-handle/src/components/editor/examples/block-handle/index.ts delete mode 100644 vue-block-handle/src/components/editor/sample/sample-doc-block-handle.ts delete mode 100644 vue-block-handle/src/components/editor/ui/block-handle/block-handle.vue delete mode 100644 vue-block-handle/src/components/editor/ui/block-handle/index.ts delete mode 100644 vue-block-handle/src/components/editor/ui/code-block-view/code-block-view.vue delete mode 100644 vue-block-handle/src/components/editor/ui/code-block-view/index.ts delete mode 100644 vue-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.vue delete mode 100644 vue-block-handle/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 vue-block-handle/src/main.ts delete mode 100644 vue-block-handle/tsconfig.app.json delete mode 100644 vue-block-handle/tsconfig.json delete mode 100644 vue-block-handle/tsconfig.node.json delete mode 100644 vue-block-handle/vite.config.ts delete mode 100644 vue-blockquote/.gitignore delete mode 100644 vue-blockquote/README.md delete mode 100644 vue-blockquote/index.html delete mode 100644 vue-blockquote/package.json delete mode 100644 vue-blockquote/src/App.vue delete mode 100644 vue-blockquote/src/app.css delete mode 100644 vue-blockquote/src/components/editor/examples/blockquote/editor.vue delete mode 100644 vue-blockquote/src/components/editor/examples/blockquote/extension.ts delete mode 100644 vue-blockquote/src/components/editor/examples/blockquote/index.ts delete mode 100644 vue-blockquote/src/components/editor/ui/button/button.vue delete mode 100644 vue-blockquote/src/components/editor/ui/button/index.ts delete mode 100644 vue-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-blockquote/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-blockquote/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-blockquote/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-blockquote/src/main.ts delete mode 100644 vue-blockquote/tsconfig.app.json delete mode 100644 vue-blockquote/tsconfig.json delete mode 100644 vue-blockquote/tsconfig.node.json delete mode 100644 vue-blockquote/vite.config.ts delete mode 100644 vue-bold/.gitignore delete mode 100644 vue-bold/README.md delete mode 100644 vue-bold/index.html delete mode 100644 vue-bold/package.json delete mode 100644 vue-bold/src/App.vue delete mode 100644 vue-bold/src/app.css delete mode 100644 vue-bold/src/components/editor/examples/bold/editor.vue delete mode 100644 vue-bold/src/components/editor/examples/bold/extension.ts delete mode 100644 vue-bold/src/components/editor/examples/bold/index.ts delete mode 100644 vue-bold/src/components/editor/sample/sample-doc-bold.ts delete mode 100644 vue-bold/src/components/editor/ui/button/button.vue delete mode 100644 vue-bold/src/components/editor/ui/button/index.ts delete mode 100644 vue-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-bold/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-bold/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-bold/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-bold/src/main.ts delete mode 100644 vue-bold/tsconfig.app.json delete mode 100644 vue-bold/tsconfig.json delete mode 100644 vue-bold/tsconfig.node.json delete mode 100644 vue-bold/vite.config.ts delete mode 100644 vue-change-tracking/.gitignore delete mode 100644 vue-change-tracking/README.md delete mode 100644 vue-change-tracking/index.html delete mode 100644 vue-change-tracking/package.json delete mode 100644 vue-change-tracking/src/App.vue delete mode 100644 vue-change-tracking/src/app.css delete mode 100644 vue-change-tracking/src/components/editor/examples/change-tracking/editor-diff.vue delete mode 100644 vue-change-tracking/src/components/editor/examples/change-tracking/editor-main.vue delete mode 100644 vue-change-tracking/src/components/editor/examples/change-tracking/editor.vue delete mode 100644 vue-change-tracking/src/components/editor/examples/change-tracking/index.ts delete mode 100644 vue-change-tracking/src/main.ts delete mode 100644 vue-change-tracking/tsconfig.app.json delete mode 100644 vue-change-tracking/tsconfig.json delete mode 100644 vue-change-tracking/tsconfig.node.json delete mode 100644 vue-change-tracking/vite.config.ts delete mode 100644 vue-code-block-themes/.gitignore delete mode 100644 vue-code-block-themes/README.md delete mode 100644 vue-code-block-themes/index.html delete mode 100644 vue-code-block-themes/package.json delete mode 100644 vue-code-block-themes/src/App.vue delete mode 100644 vue-code-block-themes/src/app.css delete mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/editor.vue delete mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts delete mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/index.ts delete mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.vue delete mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.vue delete mode 100644 vue-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 vue-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.vue delete mode 100644 vue-code-block-themes/src/components/editor/ui/code-block-view/index.ts delete mode 100644 vue-code-block-themes/src/main.ts delete mode 100644 vue-code-block-themes/tsconfig.app.json delete mode 100644 vue-code-block-themes/tsconfig.json delete mode 100644 vue-code-block-themes/tsconfig.node.json delete mode 100644 vue-code-block-themes/vite.config.ts delete mode 100644 vue-code-block/.gitignore delete mode 100644 vue-code-block/README.md delete mode 100644 vue-code-block/index.html delete mode 100644 vue-code-block/package.json delete mode 100644 vue-code-block/src/App.vue delete mode 100644 vue-code-block/src/app.css delete mode 100644 vue-code-block/src/components/editor/examples/code-block/editor.vue delete mode 100644 vue-code-block/src/components/editor/examples/code-block/extension.ts delete mode 100644 vue-code-block/src/components/editor/examples/code-block/index.ts delete mode 100644 vue-code-block/src/components/editor/sample/sample-doc-code-block.ts delete mode 100644 vue-code-block/src/components/editor/ui/button/button.vue delete mode 100644 vue-code-block/src/components/editor/ui/button/index.ts delete mode 100644 vue-code-block/src/components/editor/ui/code-block-view/code-block-view.vue delete mode 100644 vue-code-block/src/components/editor/ui/code-block-view/index.ts delete mode 100644 vue-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-code-block/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-code-block/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-code-block/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-code-block/src/main.ts delete mode 100644 vue-code-block/tsconfig.app.json delete mode 100644 vue-code-block/tsconfig.json delete mode 100644 vue-code-block/tsconfig.node.json delete mode 100644 vue-code-block/vite.config.ts delete mode 100644 vue-code/.gitignore delete mode 100644 vue-code/README.md delete mode 100644 vue-code/index.html delete mode 100644 vue-code/package.json delete mode 100644 vue-code/src/App.vue delete mode 100644 vue-code/src/app.css delete mode 100644 vue-code/src/components/editor/examples/code/editor.vue delete mode 100644 vue-code/src/components/editor/examples/code/extension.ts delete mode 100644 vue-code/src/components/editor/examples/code/index.ts delete mode 100644 vue-code/src/components/editor/sample/sample-doc-code.ts delete mode 100644 vue-code/src/components/editor/ui/button/button.vue delete mode 100644 vue-code/src/components/editor/ui/button/index.ts delete mode 100644 vue-code/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-code/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-code/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-code/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-code/src/main.ts delete mode 100644 vue-code/tsconfig.app.json delete mode 100644 vue-code/tsconfig.json delete mode 100644 vue-code/tsconfig.node.json delete mode 100644 vue-code/vite.config.ts delete mode 100644 vue-drop-cursor/.gitignore delete mode 100644 vue-drop-cursor/README.md delete mode 100644 vue-drop-cursor/index.html delete mode 100644 vue-drop-cursor/package.json delete mode 100644 vue-drop-cursor/src/App.vue delete mode 100644 vue-drop-cursor/src/app.css delete mode 100644 vue-drop-cursor/src/components/editor/examples/drop-cursor/editor.vue delete mode 100644 vue-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts delete mode 100644 vue-drop-cursor/src/components/editor/examples/drop-cursor/index.ts delete mode 100644 vue-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts delete mode 100644 vue-drop-cursor/src/main.ts delete mode 100644 vue-drop-cursor/tsconfig.app.json delete mode 100644 vue-drop-cursor/tsconfig.json delete mode 100644 vue-drop-cursor/tsconfig.node.json delete mode 100644 vue-drop-cursor/vite.config.ts delete mode 100644 vue-emoji-rules/.gitignore delete mode 100644 vue-emoji-rules/README.md delete mode 100644 vue-emoji-rules/index.html delete mode 100644 vue-emoji-rules/package.json delete mode 100644 vue-emoji-rules/src/App.vue delete mode 100644 vue-emoji-rules/src/app.css delete mode 100644 vue-emoji-rules/src/components/editor/examples/emoji-rules/editor.vue delete mode 100644 vue-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts delete mode 100644 vue-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts delete mode 100644 vue-emoji-rules/src/components/editor/examples/emoji-rules/index.ts delete mode 100644 vue-emoji-rules/src/main.ts delete mode 100644 vue-emoji-rules/tsconfig.app.json delete mode 100644 vue-emoji-rules/tsconfig.json delete mode 100644 vue-emoji-rules/tsconfig.node.json delete mode 100644 vue-emoji-rules/vite.config.ts delete mode 100644 vue-full/.gitignore delete mode 100644 vue-full/README.md delete mode 100644 vue-full/index.html delete mode 100644 vue-full/package.json delete mode 100644 vue-full/src/App.vue delete mode 100644 vue-full/src/app.css delete mode 100644 vue-full/src/components/editor/examples/full/editor.vue delete mode 100644 vue-full/src/components/editor/examples/full/extension.ts delete mode 100644 vue-full/src/components/editor/examples/full/index.ts delete mode 100644 vue-full/src/components/editor/sample/katex.ts delete mode 100644 vue-full/src/components/editor/sample/sample-doc-full.ts delete mode 100644 vue-full/src/components/editor/sample/sample-tag-data.ts delete mode 100644 vue-full/src/components/editor/sample/sample-uploader.ts delete mode 100644 vue-full/src/components/editor/sample/sample-user-data.ts delete mode 100644 vue-full/src/components/editor/ui/block-handle/block-handle.vue delete mode 100644 vue-full/src/components/editor/ui/block-handle/index.ts delete mode 100644 vue-full/src/components/editor/ui/button/button.vue delete mode 100644 vue-full/src/components/editor/ui/button/index.ts delete mode 100644 vue-full/src/components/editor/ui/code-block-view/code-block-view.vue delete mode 100644 vue-full/src/components/editor/ui/code-block-view/index.ts delete mode 100644 vue-full/src/components/editor/ui/drop-indicator/drop-indicator.vue delete mode 100644 vue-full/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 vue-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-full/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-full/src/components/editor/ui/image-view/image-view.vue delete mode 100644 vue-full/src/components/editor/ui/image-view/index.ts delete mode 100644 vue-full/src/components/editor/ui/inline-menu/index.ts delete mode 100644 vue-full/src/components/editor/ui/inline-menu/inline-menu.vue delete mode 100644 vue-full/src/components/editor/ui/slash-menu/index.ts delete mode 100644 vue-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue delete mode 100644 vue-full/src/components/editor/ui/slash-menu/slash-menu-item.vue delete mode 100644 vue-full/src/components/editor/ui/slash-menu/slash-menu.vue delete mode 100644 vue-full/src/components/editor/ui/table-handle/index.ts delete mode 100644 vue-full/src/components/editor/ui/table-handle/table-handle.vue delete mode 100644 vue-full/src/components/editor/ui/tag-menu/index.ts delete mode 100644 vue-full/src/components/editor/ui/tag-menu/tag-menu.vue delete mode 100644 vue-full/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-full/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-full/src/components/editor/ui/user-menu/index.ts delete mode 100644 vue-full/src/components/editor/ui/user-menu/user-menu.vue delete mode 100644 vue-full/src/main.ts delete mode 100644 vue-full/tsconfig.app.json delete mode 100644 vue-full/tsconfig.json delete mode 100644 vue-full/tsconfig.node.json delete mode 100644 vue-full/vite.config.ts delete mode 100644 vue-gap-cursor/.gitignore delete mode 100644 vue-gap-cursor/README.md delete mode 100644 vue-gap-cursor/index.html delete mode 100644 vue-gap-cursor/package.json delete mode 100644 vue-gap-cursor/src/App.vue delete mode 100644 vue-gap-cursor/src/app.css delete mode 100644 vue-gap-cursor/src/components/editor/examples/gap-cursor/editor.vue delete mode 100644 vue-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts delete mode 100644 vue-gap-cursor/src/components/editor/examples/gap-cursor/index.ts delete mode 100644 vue-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts delete mode 100644 vue-gap-cursor/src/main.ts delete mode 100644 vue-gap-cursor/tsconfig.app.json delete mode 100644 vue-gap-cursor/tsconfig.json delete mode 100644 vue-gap-cursor/tsconfig.node.json delete mode 100644 vue-gap-cursor/vite.config.ts delete mode 100644 vue-hard-break/.gitignore delete mode 100644 vue-hard-break/README.md delete mode 100644 vue-hard-break/index.html delete mode 100644 vue-hard-break/package.json delete mode 100644 vue-hard-break/src/App.vue delete mode 100644 vue-hard-break/src/app.css delete mode 100644 vue-hard-break/src/components/editor/examples/hard-break/editor.vue delete mode 100644 vue-hard-break/src/components/editor/examples/hard-break/extension.ts delete mode 100644 vue-hard-break/src/components/editor/examples/hard-break/index.ts delete mode 100644 vue-hard-break/src/components/editor/examples/hard-break/toolbar.vue delete mode 100644 vue-hard-break/src/components/editor/sample/sample-doc-hard-break.ts delete mode 100644 vue-hard-break/src/components/editor/ui/button/button.vue delete mode 100644 vue-hard-break/src/components/editor/ui/button/index.ts delete mode 100644 vue-hard-break/src/main.ts delete mode 100644 vue-hard-break/tsconfig.app.json delete mode 100644 vue-hard-break/tsconfig.json delete mode 100644 vue-hard-break/tsconfig.node.json delete mode 100644 vue-hard-break/vite.config.ts delete mode 100644 vue-heading/.gitignore delete mode 100644 vue-heading/README.md delete mode 100644 vue-heading/index.html delete mode 100644 vue-heading/package.json delete mode 100644 vue-heading/src/App.vue delete mode 100644 vue-heading/src/app.css delete mode 100644 vue-heading/src/components/editor/examples/heading/editor.vue delete mode 100644 vue-heading/src/components/editor/examples/heading/extension.ts delete mode 100644 vue-heading/src/components/editor/examples/heading/index.ts delete mode 100644 vue-heading/src/components/editor/sample/sample-doc-heading.ts delete mode 100644 vue-heading/src/components/editor/ui/button/button.vue delete mode 100644 vue-heading/src/components/editor/ui/button/index.ts delete mode 100644 vue-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-heading/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-heading/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-heading/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-heading/src/main.ts delete mode 100644 vue-heading/tsconfig.app.json delete mode 100644 vue-heading/tsconfig.json delete mode 100644 vue-heading/tsconfig.node.json delete mode 100644 vue-heading/vite.config.ts delete mode 100644 vue-highlight/.gitignore delete mode 100644 vue-highlight/README.md delete mode 100644 vue-highlight/index.html delete mode 100644 vue-highlight/package.json delete mode 100644 vue-highlight/src/App.vue delete mode 100644 vue-highlight/src/app.css delete mode 100644 vue-highlight/src/components/editor/examples/highlight/editor.vue delete mode 100644 vue-highlight/src/components/editor/examples/highlight/extension.ts delete mode 100644 vue-highlight/src/components/editor/examples/highlight/index.ts delete mode 100644 vue-highlight/src/components/editor/examples/highlight/toolbar.vue delete mode 100644 vue-highlight/src/components/editor/sample/sample-doc-highlight.ts delete mode 100644 vue-highlight/src/components/editor/ui/button/button.vue delete mode 100644 vue-highlight/src/components/editor/ui/button/index.ts delete mode 100644 vue-highlight/src/main.ts delete mode 100644 vue-highlight/tsconfig.app.json delete mode 100644 vue-highlight/tsconfig.json delete mode 100644 vue-highlight/tsconfig.node.json delete mode 100644 vue-highlight/vite.config.ts delete mode 100644 vue-horizontal-rule/.gitignore delete mode 100644 vue-horizontal-rule/README.md delete mode 100644 vue-horizontal-rule/index.html delete mode 100644 vue-horizontal-rule/package.json delete mode 100644 vue-horizontal-rule/src/App.vue delete mode 100644 vue-horizontal-rule/src/app.css delete mode 100644 vue-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.vue delete mode 100644 vue-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts delete mode 100644 vue-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts delete mode 100644 vue-horizontal-rule/src/components/editor/ui/button/button.vue delete mode 100644 vue-horizontal-rule/src/components/editor/ui/button/index.ts delete mode 100644 vue-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-horizontal-rule/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-horizontal-rule/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-horizontal-rule/src/main.ts delete mode 100644 vue-horizontal-rule/tsconfig.app.json delete mode 100644 vue-horizontal-rule/tsconfig.json delete mode 100644 vue-horizontal-rule/tsconfig.node.json delete mode 100644 vue-horizontal-rule/vite.config.ts delete mode 100644 vue-image-view/.gitignore delete mode 100644 vue-image-view/README.md delete mode 100644 vue-image-view/index.html delete mode 100644 vue-image-view/package.json delete mode 100644 vue-image-view/src/App.vue delete mode 100644 vue-image-view/src/app.css delete mode 100644 vue-image-view/src/components/editor/examples/image-view/editor.vue delete mode 100644 vue-image-view/src/components/editor/examples/image-view/extension.ts delete mode 100644 vue-image-view/src/components/editor/examples/image-view/index.ts delete mode 100644 vue-image-view/src/components/editor/sample/sample-doc-image.ts delete mode 100644 vue-image-view/src/components/editor/sample/sample-uploader.ts delete mode 100644 vue-image-view/src/components/editor/ui/image-view/image-view.vue delete mode 100644 vue-image-view/src/components/editor/ui/image-view/index.ts delete mode 100644 vue-image-view/src/main.ts delete mode 100644 vue-image-view/tsconfig.app.json delete mode 100644 vue-image-view/tsconfig.json delete mode 100644 vue-image-view/tsconfig.node.json delete mode 100644 vue-image-view/vite.config.ts delete mode 100644 vue-inline-menu/.gitignore delete mode 100644 vue-inline-menu/README.md delete mode 100644 vue-inline-menu/index.html delete mode 100644 vue-inline-menu/package.json delete mode 100644 vue-inline-menu/src/App.vue delete mode 100644 vue-inline-menu/src/app.css delete mode 100644 vue-inline-menu/src/components/editor/examples/inline-menu/editor.vue delete mode 100644 vue-inline-menu/src/components/editor/examples/inline-menu/extension.ts delete mode 100644 vue-inline-menu/src/components/editor/examples/inline-menu/index.ts delete mode 100644 vue-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts delete mode 100644 vue-inline-menu/src/components/editor/ui/button/button.vue delete mode 100644 vue-inline-menu/src/components/editor/ui/button/index.ts delete mode 100644 vue-inline-menu/src/components/editor/ui/inline-menu/index.ts delete mode 100644 vue-inline-menu/src/components/editor/ui/inline-menu/inline-menu.vue delete mode 100644 vue-inline-menu/src/main.ts delete mode 100644 vue-inline-menu/tsconfig.app.json delete mode 100644 vue-inline-menu/tsconfig.json delete mode 100644 vue-inline-menu/tsconfig.node.json delete mode 100644 vue-inline-menu/vite.config.ts delete mode 100644 vue-italic/.gitignore delete mode 100644 vue-italic/README.md delete mode 100644 vue-italic/index.html delete mode 100644 vue-italic/package.json delete mode 100644 vue-italic/src/App.vue delete mode 100644 vue-italic/src/app.css delete mode 100644 vue-italic/src/components/editor/examples/italic/editor.vue delete mode 100644 vue-italic/src/components/editor/examples/italic/extension.ts delete mode 100644 vue-italic/src/components/editor/examples/italic/index.ts delete mode 100644 vue-italic/src/components/editor/sample/sample-doc-italic.ts delete mode 100644 vue-italic/src/components/editor/ui/button/button.vue delete mode 100644 vue-italic/src/components/editor/ui/button/index.ts delete mode 100644 vue-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-italic/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-italic/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-italic/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-italic/src/main.ts delete mode 100644 vue-italic/tsconfig.app.json delete mode 100644 vue-italic/tsconfig.json delete mode 100644 vue-italic/tsconfig.node.json delete mode 100644 vue-italic/vite.config.ts delete mode 100644 vue-katex/.gitignore delete mode 100644 vue-katex/README.md delete mode 100644 vue-katex/index.html delete mode 100644 vue-katex/package.json delete mode 100644 vue-katex/src/App.vue delete mode 100644 vue-katex/src/app.css delete mode 100644 vue-katex/src/components/editor/examples/katex/editor.vue delete mode 100644 vue-katex/src/components/editor/examples/katex/extension.ts delete mode 100644 vue-katex/src/components/editor/examples/katex/index.ts delete mode 100644 vue-katex/src/components/editor/sample/katex.ts delete mode 100644 vue-katex/src/components/editor/sample/sample-doc-tex.ts delete mode 100644 vue-katex/src/main.ts delete mode 100644 vue-katex/tsconfig.app.json delete mode 100644 vue-katex/tsconfig.json delete mode 100644 vue-katex/tsconfig.node.json delete mode 100644 vue-katex/vite.config.ts delete mode 100644 vue-keymap/.gitignore delete mode 100644 vue-keymap/README.md delete mode 100644 vue-keymap/index.html delete mode 100644 vue-keymap/package.json delete mode 100644 vue-keymap/src/App.vue delete mode 100644 vue-keymap/src/app.css delete mode 100644 vue-keymap/src/components/editor/examples/keymap/editor.vue delete mode 100644 vue-keymap/src/components/editor/examples/keymap/extension.ts delete mode 100644 vue-keymap/src/components/editor/examples/keymap/index.ts delete mode 100644 vue-keymap/src/components/editor/examples/keymap/toolbar.vue delete mode 100644 vue-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts delete mode 100644 vue-keymap/src/components/editor/ui/button/button.vue delete mode 100644 vue-keymap/src/components/editor/ui/button/index.ts delete mode 100644 vue-keymap/src/main.ts delete mode 100644 vue-keymap/tsconfig.app.json delete mode 100644 vue-keymap/tsconfig.json delete mode 100644 vue-keymap/tsconfig.node.json delete mode 100644 vue-keymap/vite.config.ts delete mode 100644 vue-link-mark-view/.gitignore delete mode 100644 vue-link-mark-view/README.md delete mode 100644 vue-link-mark-view/index.html delete mode 100644 vue-link-mark-view/package.json delete mode 100644 vue-link-mark-view/src/App.vue delete mode 100644 vue-link-mark-view/src/app.css delete mode 100644 vue-link-mark-view/src/components/editor/examples/link-mark-view/editor.vue delete mode 100644 vue-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts delete mode 100644 vue-link-mark-view/src/components/editor/examples/link-mark-view/index.ts delete mode 100644 vue-link-mark-view/src/components/editor/examples/link-mark-view/link-view.vue delete mode 100644 vue-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts delete mode 100644 vue-link-mark-view/src/main.ts delete mode 100644 vue-link-mark-view/tsconfig.app.json delete mode 100644 vue-link-mark-view/tsconfig.json delete mode 100644 vue-link-mark-view/tsconfig.node.json delete mode 100644 vue-link-mark-view/vite.config.ts delete mode 100644 vue-link/.gitignore delete mode 100644 vue-link/README.md delete mode 100644 vue-link/index.html delete mode 100644 vue-link/package.json delete mode 100644 vue-link/src/App.vue delete mode 100644 vue-link/src/app.css delete mode 100644 vue-link/src/components/editor/examples/link/editor.vue delete mode 100644 vue-link/src/components/editor/examples/link/extension.ts delete mode 100644 vue-link/src/components/editor/examples/link/index.ts delete mode 100644 vue-link/src/components/editor/sample/sample-doc-link.ts delete mode 100644 vue-link/src/components/editor/ui/button/button.vue delete mode 100644 vue-link/src/components/editor/ui/button/index.ts delete mode 100644 vue-link/src/components/editor/ui/inline-menu/index.ts delete mode 100644 vue-link/src/components/editor/ui/inline-menu/inline-menu.vue delete mode 100644 vue-link/src/main.ts delete mode 100644 vue-link/tsconfig.app.json delete mode 100644 vue-link/tsconfig.json delete mode 100644 vue-link/tsconfig.node.json delete mode 100644 vue-link/vite.config.ts delete mode 100644 vue-list-custom-checkbox/.gitignore delete mode 100644 vue-list-custom-checkbox/README.md delete mode 100644 vue-list-custom-checkbox/index.html delete mode 100644 vue-list-custom-checkbox/package.json delete mode 100644 vue-list-custom-checkbox/src/App.vue delete mode 100644 vue-list-custom-checkbox/src/app.css delete mode 100644 vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css delete mode 100644 vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.vue delete mode 100644 vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts delete mode 100644 vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts delete mode 100644 vue-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts delete mode 100644 vue-list-custom-checkbox/src/components/editor/ui/button/button.vue delete mode 100644 vue-list-custom-checkbox/src/components/editor/ui/button/index.ts delete mode 100644 vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-list-custom-checkbox/src/main.ts delete mode 100644 vue-list-custom-checkbox/tsconfig.app.json delete mode 100644 vue-list-custom-checkbox/tsconfig.json delete mode 100644 vue-list-custom-checkbox/tsconfig.node.json delete mode 100644 vue-list-custom-checkbox/vite.config.ts delete mode 100644 vue-list/.gitignore delete mode 100644 vue-list/README.md delete mode 100644 vue-list/index.html delete mode 100644 vue-list/package.json delete mode 100644 vue-list/src/App.vue delete mode 100644 vue-list/src/app.css delete mode 100644 vue-list/src/components/editor/examples/list/editor.vue delete mode 100644 vue-list/src/components/editor/examples/list/extension.ts delete mode 100644 vue-list/src/components/editor/examples/list/index.ts delete mode 100644 vue-list/src/components/editor/sample/sample-doc-list.ts delete mode 100644 vue-list/src/components/editor/ui/button/button.vue delete mode 100644 vue-list/src/components/editor/ui/button/index.ts delete mode 100644 vue-list/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-list/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-list/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-list/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-list/src/main.ts delete mode 100644 vue-list/tsconfig.app.json delete mode 100644 vue-list/tsconfig.json delete mode 100644 vue-list/tsconfig.node.json delete mode 100644 vue-list/vite.config.ts delete mode 100644 vue-loro/.gitignore delete mode 100644 vue-loro/README.md delete mode 100644 vue-loro/index.html delete mode 100644 vue-loro/package.json delete mode 100644 vue-loro/src/App.vue delete mode 100644 vue-loro/src/app.css delete mode 100644 vue-loro/src/components/editor/examples/loro/editor-component.vue delete mode 100644 vue-loro/src/components/editor/examples/loro/editor.vue delete mode 100644 vue-loro/src/components/editor/examples/loro/extension.ts delete mode 100644 vue-loro/src/components/editor/examples/loro/index.ts delete mode 100644 vue-loro/src/components/editor/ui/button/button.vue delete mode 100644 vue-loro/src/components/editor/ui/button/index.ts delete mode 100644 vue-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-loro/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-loro/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-loro/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-loro/src/main.ts delete mode 100644 vue-loro/tsconfig.app.json delete mode 100644 vue-loro/tsconfig.json delete mode 100644 vue-loro/tsconfig.node.json delete mode 100644 vue-loro/vite.config.ts delete mode 100644 vue-mark-rule/.gitignore delete mode 100644 vue-mark-rule/README.md delete mode 100644 vue-mark-rule/index.html delete mode 100644 vue-mark-rule/package.json delete mode 100644 vue-mark-rule/src/App.vue delete mode 100644 vue-mark-rule/src/app.css delete mode 100644 vue-mark-rule/src/components/editor/examples/mark-rule/editor.vue delete mode 100644 vue-mark-rule/src/components/editor/examples/mark-rule/extension.ts delete mode 100644 vue-mark-rule/src/components/editor/examples/mark-rule/index.ts delete mode 100644 vue-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts delete mode 100644 vue-mark-rule/src/main.ts delete mode 100644 vue-mark-rule/tsconfig.app.json delete mode 100644 vue-mark-rule/tsconfig.json delete mode 100644 vue-mark-rule/tsconfig.node.json delete mode 100644 vue-mark-rule/vite.config.ts delete mode 100644 vue-minimal/.gitignore delete mode 100644 vue-minimal/README.md delete mode 100644 vue-minimal/index.html delete mode 100644 vue-minimal/package.json delete mode 100644 vue-minimal/src/App.vue delete mode 100644 vue-minimal/src/app.css delete mode 100644 vue-minimal/src/components/editor/examples/minimal/editor.vue delete mode 100644 vue-minimal/src/components/editor/examples/minimal/index.ts delete mode 100644 vue-minimal/src/main.ts delete mode 100644 vue-minimal/tsconfig.app.json delete mode 100644 vue-minimal/tsconfig.json delete mode 100644 vue-minimal/tsconfig.node.json delete mode 100644 vue-minimal/vite.config.ts delete mode 100644 vue-placeholder/.gitignore delete mode 100644 vue-placeholder/README.md delete mode 100644 vue-placeholder/index.html delete mode 100644 vue-placeholder/package.json delete mode 100644 vue-placeholder/src/App.vue delete mode 100644 vue-placeholder/src/app.css delete mode 100644 vue-placeholder/src/components/editor/examples/placeholder/editor.vue delete mode 100644 vue-placeholder/src/components/editor/examples/placeholder/extension.ts delete mode 100644 vue-placeholder/src/components/editor/examples/placeholder/index.ts delete mode 100644 vue-placeholder/src/main.ts delete mode 100644 vue-placeholder/tsconfig.app.json delete mode 100644 vue-placeholder/tsconfig.json delete mode 100644 vue-placeholder/tsconfig.node.json delete mode 100644 vue-placeholder/vite.config.ts delete mode 100644 vue-readonly/.gitignore delete mode 100644 vue-readonly/README.md delete mode 100644 vue-readonly/index.html delete mode 100644 vue-readonly/package.json delete mode 100644 vue-readonly/src/App.vue delete mode 100644 vue-readonly/src/app.css delete mode 100644 vue-readonly/src/components/editor/examples/readonly/editor.vue delete mode 100644 vue-readonly/src/components/editor/examples/readonly/extension.ts delete mode 100644 vue-readonly/src/components/editor/examples/readonly/index.ts delete mode 100644 vue-readonly/src/components/editor/examples/readonly/toolbar.vue delete mode 100644 vue-readonly/src/components/editor/examples/readonly/use-readonly.ts delete mode 100644 vue-readonly/src/components/editor/sample/sample-doc-readonly.ts delete mode 100644 vue-readonly/src/components/editor/ui/button/button.vue delete mode 100644 vue-readonly/src/components/editor/ui/button/index.ts delete mode 100644 vue-readonly/src/main.ts delete mode 100644 vue-readonly/tsconfig.app.json delete mode 100644 vue-readonly/tsconfig.json delete mode 100644 vue-readonly/tsconfig.node.json delete mode 100644 vue-readonly/vite.config.ts delete mode 100644 vue-rtl/.gitignore delete mode 100644 vue-rtl/README.md delete mode 100644 vue-rtl/index.html delete mode 100644 vue-rtl/package.json delete mode 100644 vue-rtl/src/App.vue delete mode 100644 vue-rtl/src/app.css delete mode 100644 vue-rtl/src/components/editor/examples/rtl/editor.vue delete mode 100644 vue-rtl/src/components/editor/examples/rtl/index.ts delete mode 100644 vue-rtl/src/components/editor/sample/sample-doc-rtl.ts delete mode 100644 vue-rtl/src/components/editor/sample/sample-uploader.ts delete mode 100644 vue-rtl/src/components/editor/ui/block-handle/block-handle.vue delete mode 100644 vue-rtl/src/components/editor/ui/block-handle/index.ts delete mode 100644 vue-rtl/src/components/editor/ui/button/button.vue delete mode 100644 vue-rtl/src/components/editor/ui/button/index.ts delete mode 100644 vue-rtl/src/components/editor/ui/drop-indicator/drop-indicator.vue delete mode 100644 vue-rtl/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 vue-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-rtl/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-rtl/src/components/editor/ui/inline-menu/index.ts delete mode 100644 vue-rtl/src/components/editor/ui/inline-menu/inline-menu.vue delete mode 100644 vue-rtl/src/components/editor/ui/slash-menu/index.ts delete mode 100644 vue-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.vue delete mode 100644 vue-rtl/src/components/editor/ui/slash-menu/slash-menu-item.vue delete mode 100644 vue-rtl/src/components/editor/ui/slash-menu/slash-menu.vue delete mode 100644 vue-rtl/src/components/editor/ui/table-handle/index.ts delete mode 100644 vue-rtl/src/components/editor/ui/table-handle/table-handle.vue delete mode 100644 vue-rtl/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-rtl/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-rtl/src/main.ts delete mode 100644 vue-rtl/tsconfig.app.json delete mode 100644 vue-rtl/tsconfig.json delete mode 100644 vue-rtl/tsconfig.node.json delete mode 100644 vue-rtl/vite.config.ts delete mode 100644 vue-save-html/.gitignore delete mode 100644 vue-save-html/README.md delete mode 100644 vue-save-html/index.html delete mode 100644 vue-save-html/package.json delete mode 100644 vue-save-html/src/App.vue delete mode 100644 vue-save-html/src/app.css delete mode 100644 vue-save-html/src/components/editor/examples/save-html/editor.vue delete mode 100644 vue-save-html/src/components/editor/examples/save-html/index.ts delete mode 100644 vue-save-html/src/main.ts delete mode 100644 vue-save-html/tsconfig.app.json delete mode 100644 vue-save-html/tsconfig.json delete mode 100644 vue-save-html/tsconfig.node.json delete mode 100644 vue-save-html/vite.config.ts delete mode 100644 vue-save-json/.gitignore delete mode 100644 vue-save-json/README.md delete mode 100644 vue-save-json/index.html delete mode 100644 vue-save-json/package.json delete mode 100644 vue-save-json/src/App.vue delete mode 100644 vue-save-json/src/app.css delete mode 100644 vue-save-json/src/components/editor/examples/save-json/editor.vue delete mode 100644 vue-save-json/src/components/editor/examples/save-json/index.ts delete mode 100644 vue-save-json/src/main.ts delete mode 100644 vue-save-json/tsconfig.app.json delete mode 100644 vue-save-json/tsconfig.json delete mode 100644 vue-save-json/tsconfig.node.json delete mode 100644 vue-save-json/vite.config.ts delete mode 100644 vue-save-markdown/.gitignore delete mode 100644 vue-save-markdown/README.md delete mode 100644 vue-save-markdown/index.html delete mode 100644 vue-save-markdown/package.json delete mode 100644 vue-save-markdown/src/App.vue delete mode 100644 vue-save-markdown/src/app.css delete mode 100644 vue-save-markdown/src/components/editor/examples/save-markdown/editor.vue delete mode 100644 vue-save-markdown/src/components/editor/examples/save-markdown/index.ts delete mode 100644 vue-save-markdown/src/components/editor/examples/save-markdown/markdown.ts delete mode 100644 vue-save-markdown/src/main.ts delete mode 100644 vue-save-markdown/tsconfig.app.json delete mode 100644 vue-save-markdown/tsconfig.json delete mode 100644 vue-save-markdown/tsconfig.node.json delete mode 100644 vue-save-markdown/vite.config.ts delete mode 100644 vue-search/.gitignore delete mode 100644 vue-search/README.md delete mode 100644 vue-search/index.html delete mode 100644 vue-search/package.json delete mode 100644 vue-search/src/App.vue delete mode 100644 vue-search/src/app.css delete mode 100644 vue-search/src/components/editor/examples/search/editor.vue delete mode 100644 vue-search/src/components/editor/examples/search/extension.ts delete mode 100644 vue-search/src/components/editor/examples/search/index.ts delete mode 100644 vue-search/src/components/editor/sample/sample-doc-search.ts delete mode 100644 vue-search/src/components/editor/ui/button/button.vue delete mode 100644 vue-search/src/components/editor/ui/button/index.ts delete mode 100644 vue-search/src/components/editor/ui/search/index.ts delete mode 100644 vue-search/src/components/editor/ui/search/search.vue delete mode 100644 vue-search/src/main.ts delete mode 100644 vue-search/tsconfig.app.json delete mode 100644 vue-search/tsconfig.json delete mode 100644 vue-search/tsconfig.node.json delete mode 100644 vue-search/vite.config.ts delete mode 100644 vue-slash-menu/.gitignore delete mode 100644 vue-slash-menu/README.md delete mode 100644 vue-slash-menu/index.html delete mode 100644 vue-slash-menu/package.json delete mode 100644 vue-slash-menu/src/App.vue delete mode 100644 vue-slash-menu/src/app.css delete mode 100644 vue-slash-menu/src/components/editor/examples/slash-menu/editor.vue delete mode 100644 vue-slash-menu/src/components/editor/examples/slash-menu/extension.ts delete mode 100644 vue-slash-menu/src/components/editor/examples/slash-menu/index.ts delete mode 100644 vue-slash-menu/src/components/editor/ui/slash-menu/index.ts delete mode 100644 vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.vue delete mode 100644 vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.vue delete mode 100644 vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu.vue delete mode 100644 vue-slash-menu/src/main.ts delete mode 100644 vue-slash-menu/tsconfig.app.json delete mode 100644 vue-slash-menu/tsconfig.json delete mode 100644 vue-slash-menu/tsconfig.node.json delete mode 100644 vue-slash-menu/vite.config.ts delete mode 100644 vue-strike/.gitignore delete mode 100644 vue-strike/README.md delete mode 100644 vue-strike/index.html delete mode 100644 vue-strike/package.json delete mode 100644 vue-strike/src/App.vue delete mode 100644 vue-strike/src/app.css delete mode 100644 vue-strike/src/components/editor/examples/strike/editor.vue delete mode 100644 vue-strike/src/components/editor/examples/strike/extension.ts delete mode 100644 vue-strike/src/components/editor/examples/strike/index.ts delete mode 100644 vue-strike/src/components/editor/examples/strike/toolbar.vue delete mode 100644 vue-strike/src/components/editor/sample/sample-doc-strike.ts delete mode 100644 vue-strike/src/components/editor/ui/button/button.vue delete mode 100644 vue-strike/src/components/editor/ui/button/index.ts delete mode 100644 vue-strike/src/main.ts delete mode 100644 vue-strike/tsconfig.app.json delete mode 100644 vue-strike/tsconfig.json delete mode 100644 vue-strike/tsconfig.node.json delete mode 100644 vue-strike/vite.config.ts delete mode 100644 vue-sub-sup/.gitignore delete mode 100644 vue-sub-sup/README.md delete mode 100644 vue-sub-sup/index.html delete mode 100644 vue-sub-sup/package.json delete mode 100644 vue-sub-sup/src/App.vue delete mode 100644 vue-sub-sup/src/app.css delete mode 100644 vue-sub-sup/src/components/editor/examples/sub-sup/editor.vue delete mode 100644 vue-sub-sup/src/components/editor/examples/sub-sup/extension.ts delete mode 100644 vue-sub-sup/src/components/editor/examples/sub-sup/index.ts delete mode 100644 vue-sub-sup/src/components/editor/examples/sub-sup/toolbar.vue delete mode 100644 vue-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts delete mode 100644 vue-sub-sup/src/components/editor/ui/button/button.vue delete mode 100644 vue-sub-sup/src/components/editor/ui/button/index.ts delete mode 100644 vue-sub-sup/src/main.ts delete mode 100644 vue-sub-sup/tsconfig.app.json delete mode 100644 vue-sub-sup/tsconfig.json delete mode 100644 vue-sub-sup/tsconfig.node.json delete mode 100644 vue-sub-sup/vite.config.ts delete mode 100644 vue-table/.gitignore delete mode 100644 vue-table/README.md delete mode 100644 vue-table/index.html delete mode 100644 vue-table/package.json delete mode 100644 vue-table/src/App.vue delete mode 100644 vue-table/src/app.css delete mode 100644 vue-table/src/components/editor/examples/table/editor.vue delete mode 100644 vue-table/src/components/editor/examples/table/extension.ts delete mode 100644 vue-table/src/components/editor/examples/table/index.ts delete mode 100644 vue-table/src/components/editor/sample/sample-doc-table.ts delete mode 100644 vue-table/src/components/editor/ui/table-handle/index.ts delete mode 100644 vue-table/src/components/editor/ui/table-handle/table-handle.vue delete mode 100644 vue-table/src/main.ts delete mode 100644 vue-table/tsconfig.app.json delete mode 100644 vue-table/tsconfig.json delete mode 100644 vue-table/tsconfig.node.json delete mode 100644 vue-table/vite.config.ts delete mode 100644 vue-text-align/.gitignore delete mode 100644 vue-text-align/README.md delete mode 100644 vue-text-align/index.html delete mode 100644 vue-text-align/package.json delete mode 100644 vue-text-align/src/App.vue delete mode 100644 vue-text-align/src/app.css delete mode 100644 vue-text-align/src/components/editor/examples/text-align/editor.vue delete mode 100644 vue-text-align/src/components/editor/examples/text-align/extension.ts delete mode 100644 vue-text-align/src/components/editor/examples/text-align/index.ts delete mode 100644 vue-text-align/src/components/editor/examples/text-align/toolbar.vue delete mode 100644 vue-text-align/src/components/editor/sample/sample-doc-text-align.ts delete mode 100644 vue-text-align/src/components/editor/ui/button/button.vue delete mode 100644 vue-text-align/src/components/editor/ui/button/index.ts delete mode 100644 vue-text-align/src/main.ts delete mode 100644 vue-text-align/tsconfig.app.json delete mode 100644 vue-text-align/tsconfig.json delete mode 100644 vue-text-align/tsconfig.node.json delete mode 100644 vue-text-align/vite.config.ts delete mode 100644 vue-text-color/.gitignore delete mode 100644 vue-text-color/README.md delete mode 100644 vue-text-color/index.html delete mode 100644 vue-text-color/package.json delete mode 100644 vue-text-color/src/App.vue delete mode 100644 vue-text-color/src/app.css delete mode 100644 vue-text-color/src/components/editor/examples/text-color/editor.vue delete mode 100644 vue-text-color/src/components/editor/examples/text-color/extension.ts delete mode 100644 vue-text-color/src/components/editor/examples/text-color/index.ts delete mode 100644 vue-text-color/src/components/editor/examples/text-color/inline-menu.vue delete mode 100644 vue-text-color/src/components/editor/sample/sample-doc-text-color.ts delete mode 100644 vue-text-color/src/components/editor/ui/button/button.vue delete mode 100644 vue-text-color/src/components/editor/ui/button/index.ts delete mode 100644 vue-text-color/src/main.ts delete mode 100644 vue-text-color/tsconfig.app.json delete mode 100644 vue-text-color/tsconfig.json delete mode 100644 vue-text-color/tsconfig.node.json delete mode 100644 vue-text-color/vite.config.ts delete mode 100644 vue-toolbar/.gitignore delete mode 100644 vue-toolbar/README.md delete mode 100644 vue-toolbar/index.html delete mode 100644 vue-toolbar/package.json delete mode 100644 vue-toolbar/src/App.vue delete mode 100644 vue-toolbar/src/app.css delete mode 100644 vue-toolbar/src/components/editor/examples/toolbar/editor.vue delete mode 100644 vue-toolbar/src/components/editor/examples/toolbar/extension.ts delete mode 100644 vue-toolbar/src/components/editor/examples/toolbar/index.ts delete mode 100644 vue-toolbar/src/components/editor/sample/sample-uploader.ts delete mode 100644 vue-toolbar/src/components/editor/ui/button/button.vue delete mode 100644 vue-toolbar/src/components/editor/ui/button/index.ts delete mode 100644 vue-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-toolbar/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-toolbar/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-toolbar/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-toolbar/src/main.ts delete mode 100644 vue-toolbar/tsconfig.app.json delete mode 100644 vue-toolbar/tsconfig.json delete mode 100644 vue-toolbar/tsconfig.node.json delete mode 100644 vue-toolbar/vite.config.ts delete mode 100644 vue-tweet/.gitignore delete mode 100644 vue-tweet/README.md delete mode 100644 vue-tweet/index.html delete mode 100644 vue-tweet/package.json delete mode 100644 vue-tweet/src/App.vue delete mode 100644 vue-tweet/src/app.css delete mode 100644 vue-tweet/src/components/editor/examples/tweet/editor.vue delete mode 100644 vue-tweet/src/components/editor/examples/tweet/extension.ts delete mode 100644 vue-tweet/src/components/editor/examples/tweet/index.ts delete mode 100644 vue-tweet/src/components/editor/examples/tweet/method-select.vue delete mode 100644 vue-tweet/src/components/editor/examples/tweet/tweet-view.vue delete mode 100644 vue-tweet/src/components/editor/sample/sample-doc-tweet.ts delete mode 100644 vue-tweet/src/main.ts delete mode 100644 vue-tweet/tsconfig.app.json delete mode 100644 vue-tweet/tsconfig.json delete mode 100644 vue-tweet/tsconfig.node.json delete mode 100644 vue-tweet/vite.config.ts delete mode 100644 vue-typography/.gitignore delete mode 100644 vue-typography/README.md delete mode 100644 vue-typography/index.html delete mode 100644 vue-typography/package.json delete mode 100644 vue-typography/src/App.vue delete mode 100644 vue-typography/src/app.css delete mode 100644 vue-typography/src/components/editor/examples/typography/editor.vue delete mode 100644 vue-typography/src/components/editor/examples/typography/extension.ts delete mode 100644 vue-typography/src/components/editor/examples/typography/index.ts delete mode 100644 vue-typography/src/components/editor/sample/katex.ts delete mode 100644 vue-typography/src/components/editor/sample/sample-doc-typography.ts delete mode 100644 vue-typography/src/components/editor/ui/block-handle/block-handle.vue delete mode 100644 vue-typography/src/components/editor/ui/block-handle/index.ts delete mode 100644 vue-typography/src/components/editor/ui/drop-indicator/drop-indicator.vue delete mode 100644 vue-typography/src/components/editor/ui/drop-indicator/index.ts delete mode 100644 vue-typography/src/main.ts delete mode 100644 vue-typography/tsconfig.app.json delete mode 100644 vue-typography/tsconfig.json delete mode 100644 vue-typography/tsconfig.node.json delete mode 100644 vue-typography/vite.config.ts delete mode 100644 vue-underline/.gitignore delete mode 100644 vue-underline/README.md delete mode 100644 vue-underline/index.html delete mode 100644 vue-underline/package.json delete mode 100644 vue-underline/src/App.vue delete mode 100644 vue-underline/src/app.css delete mode 100644 vue-underline/src/components/editor/examples/underline/editor.vue delete mode 100644 vue-underline/src/components/editor/examples/underline/extension.ts delete mode 100644 vue-underline/src/components/editor/examples/underline/index.ts delete mode 100644 vue-underline/src/components/editor/sample/sample-doc-underline.ts delete mode 100644 vue-underline/src/components/editor/ui/button/button.vue delete mode 100644 vue-underline/src/components/editor/ui/button/index.ts delete mode 100644 vue-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-underline/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-underline/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-underline/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-underline/src/main.ts delete mode 100644 vue-underline/tsconfig.app.json delete mode 100644 vue-underline/tsconfig.json delete mode 100644 vue-underline/tsconfig.node.json delete mode 100644 vue-underline/vite.config.ts delete mode 100644 vue-unmount/.gitignore delete mode 100644 vue-unmount/README.md delete mode 100644 vue-unmount/index.html delete mode 100644 vue-unmount/package.json delete mode 100644 vue-unmount/src/App.vue delete mode 100644 vue-unmount/src/app.css delete mode 100644 vue-unmount/src/components/editor/examples/unmount/editor-component.vue delete mode 100644 vue-unmount/src/components/editor/examples/unmount/editor.vue delete mode 100644 vue-unmount/src/components/editor/examples/unmount/extension-component.vue delete mode 100644 vue-unmount/src/components/editor/examples/unmount/index.ts delete mode 100644 vue-unmount/src/components/editor/ui/button/button.vue delete mode 100644 vue-unmount/src/components/editor/ui/button/index.ts delete mode 100644 vue-unmount/src/components/editor/ui/inline-menu/index.ts delete mode 100644 vue-unmount/src/components/editor/ui/inline-menu/inline-menu.vue delete mode 100644 vue-unmount/src/main.ts delete mode 100644 vue-unmount/tsconfig.app.json delete mode 100644 vue-unmount/tsconfig.json delete mode 100644 vue-unmount/tsconfig.node.json delete mode 100644 vue-unmount/vite.config.ts delete mode 100644 vue-user-menu-dynamic/.gitignore delete mode 100644 vue-user-menu-dynamic/README.md delete mode 100644 vue-user-menu-dynamic/index.html delete mode 100644 vue-user-menu-dynamic/package.json delete mode 100644 vue-user-menu-dynamic/src/App.vue delete mode 100644 vue-user-menu-dynamic/src/app.css delete mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.vue delete mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts delete mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts delete mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts delete mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.vue delete mode 100644 vue-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts delete mode 100644 vue-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts delete mode 100644 vue-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts delete mode 100644 vue-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.vue delete mode 100644 vue-user-menu-dynamic/src/main.ts delete mode 100644 vue-user-menu-dynamic/tsconfig.app.json delete mode 100644 vue-user-menu-dynamic/tsconfig.json delete mode 100644 vue-user-menu-dynamic/tsconfig.node.json delete mode 100644 vue-user-menu-dynamic/vite.config.ts delete mode 100644 vue-user-menu/.gitignore delete mode 100644 vue-user-menu/README.md delete mode 100644 vue-user-menu/index.html delete mode 100644 vue-user-menu/package.json delete mode 100644 vue-user-menu/src/App.vue delete mode 100644 vue-user-menu/src/app.css delete mode 100644 vue-user-menu/src/components/editor/examples/user-menu/editor.vue delete mode 100644 vue-user-menu/src/components/editor/examples/user-menu/extension.ts delete mode 100644 vue-user-menu/src/components/editor/examples/user-menu/index.ts delete mode 100644 vue-user-menu/src/components/editor/sample/sample-tag-data.ts delete mode 100644 vue-user-menu/src/components/editor/sample/sample-user-data.ts delete mode 100644 vue-user-menu/src/components/editor/ui/tag-menu/index.ts delete mode 100644 vue-user-menu/src/components/editor/ui/tag-menu/tag-menu.vue delete mode 100644 vue-user-menu/src/components/editor/ui/user-menu/index.ts delete mode 100644 vue-user-menu/src/components/editor/ui/user-menu/user-menu.vue delete mode 100644 vue-user-menu/src/main.ts delete mode 100644 vue-user-menu/tsconfig.app.json delete mode 100644 vue-user-menu/tsconfig.json delete mode 100644 vue-user-menu/tsconfig.node.json delete mode 100644 vue-user-menu/vite.config.ts delete mode 100644 vue-word-counter/.gitignore delete mode 100644 vue-word-counter/README.md delete mode 100644 vue-word-counter/index.html delete mode 100644 vue-word-counter/package.json delete mode 100644 vue-word-counter/src/App.vue delete mode 100644 vue-word-counter/src/app.css delete mode 100644 vue-word-counter/src/components/editor/examples/word-counter/editor.vue delete mode 100644 vue-word-counter/src/components/editor/examples/word-counter/extension.ts delete mode 100644 vue-word-counter/src/components/editor/examples/word-counter/index.ts delete mode 100644 vue-word-counter/src/components/editor/sample/sample-doc-word-counter.ts delete mode 100644 vue-word-counter/src/components/editor/ui/word-counter/index.ts delete mode 100644 vue-word-counter/src/components/editor/ui/word-counter/word-counter.vue delete mode 100644 vue-word-counter/src/main.ts delete mode 100644 vue-word-counter/tsconfig.app.json delete mode 100644 vue-word-counter/tsconfig.json delete mode 100644 vue-word-counter/tsconfig.node.json delete mode 100644 vue-word-counter/vite.config.ts delete mode 100644 vue-yjs/.gitignore delete mode 100644 vue-yjs/README.md delete mode 100644 vue-yjs/index.html delete mode 100644 vue-yjs/package.json delete mode 100644 vue-yjs/src/App.vue delete mode 100644 vue-yjs/src/app.css delete mode 100644 vue-yjs/src/components/editor/examples/yjs/editor-component.vue delete mode 100644 vue-yjs/src/components/editor/examples/yjs/editor.vue delete mode 100644 vue-yjs/src/components/editor/examples/yjs/extension.ts delete mode 100644 vue-yjs/src/components/editor/examples/yjs/index.ts delete mode 100644 vue-yjs/src/components/editor/ui/button/button.vue delete mode 100644 vue-yjs/src/components/editor/ui/button/index.ts delete mode 100644 vue-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.vue delete mode 100644 vue-yjs/src/components/editor/ui/image-upload-popover/index.ts delete mode 100644 vue-yjs/src/components/editor/ui/toolbar/index.ts delete mode 100644 vue-yjs/src/components/editor/ui/toolbar/toolbar.vue delete mode 100644 vue-yjs/src/main.ts delete mode 100644 vue-yjs/tsconfig.app.json delete mode 100644 vue-yjs/tsconfig.json delete mode 100644 vue-yjs/tsconfig.node.json delete mode 100644 vue-yjs/vite.config.ts diff --git a/lit-block-handle/.gitignore b/lit-block-handle/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/lit-block-handle/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/lit-block-handle/README.md b/lit-block-handle/README.md deleted file mode 100644 index 05508d749e..0000000000 --- a/lit-block-handle/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# lit-block-handle - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-block-handle) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-block-handle) - -Run the example locally with: - -```bash -npx degit prosekit/examples/lit-block-handle lit-block-handle -cd lit-block-handle -npm install -npm run dev -``` diff --git a/lit-block-handle/index.html b/lit-block-handle/index.html deleted file mode 100644 index 9637b16269..0000000000 --- a/lit-block-handle/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - ProseKit + Lit - - - - - - - diff --git a/lit-block-handle/package.json b/lit-block-handle/package.json deleted file mode 100644 index 10af979864..0000000000 --- a/lit-block-handle/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "example-lit-block-handle", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "@lit/context": "^1.1.6", - "lit": "^3.3.2", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/lit-block-handle/src/app.css b/lit-block-handle/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/lit-block-handle/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/lit-block-handle/src/app.ts b/lit-block-handle/src/app.ts deleted file mode 100644 index 3cbf14f94d..0000000000 --- a/lit-block-handle/src/app.ts +++ /dev/null @@ -1,18 +0,0 @@ -import './app.css' -import './editor' - -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -@customElement('my-app') -export class MyApp extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-block-handle/src/components/editor/examples/block-handle/editor.ts b/lit-block-handle/src/components/editor/examples/block-handle/editor.ts deleted file mode 100644 index 0e4a1d8857..0000000000 --- a/lit-block-handle/src/components/editor/examples/block-handle/editor.ts +++ /dev/null @@ -1,99 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { ContextProvider } from '@lit/context' -import { - html, - LitElement, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import { createRef, ref, type Ref } from 'lit/directives/ref.js' -import type { Editor, NodeJSON } from 'prosekit/core' -import { createEditor } from 'prosekit/core' - -import { sampleContent } from '../../sample/sample-doc-block-handle' -import { registerLitEditorBlockHandle } from '../../ui/block-handle' -import { registerLitEditorDropIndicator } from '../../ui/drop-indicator' -import { editorContext } from '../../ui/editor-context' - -import { defineExtension } from './extension' - -export class LitEditor extends LitElement { - static override properties = { - initialContent: { - attribute: false, - } satisfies PropertyDeclaration, - } - - initialContent?: NodeJSON - - private editor?: Editor - private ref: Ref - - constructor() { - super() - this.ref = createRef() - } - - override createRenderRoot() { - return this - } - - override disconnectedCallback() { - this.editor?.unmount() - super.disconnectedCallback() - } - - override willUpdate() { - if (this.editor) { - return - } - - const extension = defineExtension() - this.editor = createEditor({ - extension, - defaultContent: this.initialContent ?? sampleContent, - }) - new ContextProvider(this, { - context: editorContext, - initialValue: this.editor, - }) - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.editor?.mount(this.ref.value) - } - - override render() { - return html` -
-
-
- - -
-
- ` - } -} - -export function registerLitEditor() { - registerLitEditorBlockHandle() - registerLitEditorDropIndicator() - - if (customElements.get('lit-editor-example-block-handle')) return - customElements.define('lit-editor-example-block-handle', LitEditor) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-example-block-handle': LitEditor - } -} diff --git a/lit-block-handle/src/components/editor/examples/block-handle/extension.ts b/lit-block-handle/src/components/editor/examples/block-handle/extension.ts deleted file mode 100644 index b5686b8c04..0000000000 --- a/lit-block-handle/src/components/editor/examples/block-handle/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union(defineBasicExtension(), defineCodeBlockView()) -} - -export type EditorExtension = ReturnType diff --git a/lit-block-handle/src/components/editor/examples/block-handle/index.ts b/lit-block-handle/src/components/editor/examples/block-handle/index.ts deleted file mode 100644 index 9eeecbbc50..0000000000 --- a/lit-block-handle/src/components/editor/examples/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/lit-block-handle/src/components/editor/sample/sample-doc-block-handle.ts deleted file mode 100644 index 3c6ccdc203..0000000000 --- a/lit-block-handle/src/components/editor/sample/sample-doc-block-handle.ts +++ /dev/null @@ -1,323 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Drag and Drop Demo', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Getting Started', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This paragraph can be moved above or below other blocks.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Different Block Types', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'You can drag paragraphs, headings, lists, code blocks, and more.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Lists Work Too', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This entire list can be dragged', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Individual list items stay together', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try moving this list around', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Ordered lists also support dragging', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The numbering updates automatically', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag this list to see it in action', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Even code blocks can be moved:', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: 'javascript', - }, - content: [ - { - type: 'text', - text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Nested Content', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This blockquote can be moved as a single unit.', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested blockquotes move together with their parent.', - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Try It Yourself', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Practice by moving this paragraph to the top of the document.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Or drag this one to between the headings above.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The drag handles make it easy to reorganize your content exactly how you want it.', - }, - ], - }, - ], -} diff --git a/lit-block-handle/src/components/editor/ui/block-handle/block-handle.ts b/lit-block-handle/src/components/editor/ui/block-handle/block-handle.ts deleted file mode 100644 index 7cc4822558..0000000000 --- a/lit-block-handle/src/components/editor/ui/block-handle/block-handle.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { ContextConsumer } from '@lit/context' -import { html, LitElement } from 'lit' -import { - registerBlockHandleAddElement, - registerBlockHandleDraggableElement, - registerBlockHandlePopupElement, - registerBlockHandlePositionerElement, - registerBlockHandleRootElement, -} from 'prosekit/lit/block-handle' - -import { editorContext } from '../editor-context' - -class LitBlockHandle extends LitElement { - declare dir: 'ltr' | 'rtl' | 'auto' - - private _editorConsumer = new ContextConsumer(this, { - context: editorContext, - subscribe: true, - }) - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - } - - override createRenderRoot() { - return this - } - - override render() { - const placement = this.dir === 'rtl' ? 'right' : 'left' - const editor = this._editorConsumer.value ?? null - - return html` - - - - -
-
- -
-
-
-
-
- ` - } -} - -export function registerLitEditorBlockHandle() { - registerBlockHandleAddElement() - registerBlockHandleDraggableElement() - registerBlockHandlePopupElement() - registerBlockHandlePositionerElement() - registerBlockHandleRootElement() - - if (customElements.get('lit-editor-block-handle')) return - customElements.define('lit-editor-block-handle', LitBlockHandle) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-block-handle': LitBlockHandle - } -} diff --git a/lit-block-handle/src/components/editor/ui/block-handle/index.ts b/lit-block-handle/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 40c59d8d74..0000000000 --- a/lit-block-handle/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorBlockHandle } from './block-handle' diff --git a/lit-block-handle/src/components/editor/ui/code-block-view/code-block-view.ts b/lit-block-handle/src/components/editor/ui/code-block-view/code-block-view.ts deleted file mode 100644 index ce30a8fd93..0000000000 --- a/lit-block-handle/src/components/editor/ui/code-block-view/code-block-view.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineNodeView } from 'prosekit/core' -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { ProseMirrorNode } from 'prosekit/pm/model' -import type { EditorView } from 'prosekit/pm/view' - -class CodeBlockNodeView { - dom: HTMLElement - contentDOM: HTMLElement - private node: ProseMirrorNode - private view: EditorView - private getPos: () => number | undefined - private select: HTMLSelectElement - private pre: HTMLPreElement - - constructor( - node: ProseMirrorNode, - view: EditorView, - getPos: () => number | undefined, - ) { - this.node = node - this.view = view - this.getPos = getPos - - const root = document.createElement('div') - root.setAttribute('data-node-view-root', 'true') - - const wrapper = document.createElement('div') - wrapper.className = - 'relative mx-2 top-3 h-0 select-none overflow-visible text-xs' - wrapper.setAttribute('contenteditable', 'false') - - this.select = document.createElement('select') - this.select.setAttribute('aria-label', 'Code block language') - this.select.className = - 'outline-unset focus:outline-unset relative box-border w-auto cursor-pointer select-none appearance-none rounded-sm border-none bg-transparent px-2 py-1 text-xs transition text-(--prosemirror-highlight) opacity-0 hover:opacity-80 [div[data-node-view-root]:hover_&]:opacity-50 hover:[div[data-node-view-root]:hover_&]:opacity-80' - - const plain = document.createElement('option') - plain.value = '' - plain.textContent = 'Plain Text' - this.select.appendChild(plain) - - for (const info of shikiBundledLanguagesInfo) { - const option = document.createElement('option') - option.value = info.id - option.textContent = info.name - this.select.appendChild(option) - } - - this.select.addEventListener('change', this.handleChange) - wrapper.appendChild(this.select) - - this.pre = document.createElement('pre') - this.contentDOM = document.createElement('code') - this.contentDOM.setAttribute('data-node-view-content', 'true') - this.contentDOM.style.whiteSpace = 'inherit' - this.pre.appendChild(this.contentDOM) - - root.appendChild(wrapper) - root.appendChild(this.pre) - - this.dom = root - this.syncAttrs() - } - - private handleChange = (event: Event) => { - const language = (event.target as HTMLSelectElement).value - const pos = this.getPos() - if (typeof pos !== 'number') return - const attrs: CodeBlockAttrs = { - ...(this.node.attrs as CodeBlockAttrs), - language, - } - this.view.dispatch(this.view.state.tr.setNodeMarkup(pos, undefined, attrs)) - } - - private syncAttrs() { - const language = (this.node.attrs as CodeBlockAttrs).language || '' - this.select.value = language - if (language) { - this.pre.setAttribute('data-language', language) - } else { - this.pre.removeAttribute('data-language') - } - } - - update(node: ProseMirrorNode) { - if (node.type !== this.node.type) return false - this.node = node - this.syncAttrs() - return true - } - - destroy() { - this.select.removeEventListener('change', this.handleChange) - } -} - -export function defineCodeBlockView(): Extension { - return defineNodeView({ - name: 'codeBlock', - constructor: (node, view, getPos) => - new CodeBlockNodeView(node, view, getPos), - }) -} diff --git a/lit-block-handle/src/components/editor/ui/code-block-view/index.ts b/lit-block-handle/src/components/editor/ui/code-block-view/index.ts deleted file mode 100644 index a96ff094eb..0000000000 --- a/lit-block-handle/src/components/editor/ui/code-block-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { defineCodeBlockView } from './code-block-view' diff --git a/lit-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.ts b/lit-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.ts deleted file mode 100644 index b18f3c6a20..0000000000 --- a/lit-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { ContextConsumer } from '@lit/context' -import { html, LitElement } from 'lit' -import { registerDropIndicatorElement } from 'prosekit/lit/drop-indicator' - -import { editorContext } from '../editor-context' - -class LitDropIndicator extends LitElement { - private _editorConsumer = new ContextConsumer(this, { - context: editorContext, - subscribe: true, - }) - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - } - - override createRenderRoot() { - return this - } - - override render() { - return html` - - ` - } -} - -export function registerLitEditorDropIndicator() { - registerDropIndicatorElement() - - if (customElements.get('lit-editor-drop-indicator')) return - customElements.define('lit-editor-drop-indicator', LitDropIndicator) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-drop-indicator': LitDropIndicator - } -} diff --git a/lit-block-handle/src/components/editor/ui/drop-indicator/index.ts b/lit-block-handle/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index f90b74e908..0000000000 --- a/lit-block-handle/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorDropIndicator } from './drop-indicator' diff --git a/lit-block-handle/src/components/editor/ui/editor-context.ts b/lit-block-handle/src/components/editor/ui/editor-context.ts deleted file mode 100644 index 7af6d3a865..0000000000 --- a/lit-block-handle/src/components/editor/ui/editor-context.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createContext } from '@lit/context' -import type { Editor } from 'prosekit/core' - -export const editorContext = createContext( - 'prosekit-editor', -) diff --git a/lit-block-handle/src/editor.ts b/lit-block-handle/src/editor.ts deleted file mode 100644 index 2c676875fb..0000000000 --- a/lit-block-handle/src/editor.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { registerLitEditor } from './components/editor/examples/block-handle' -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -registerLitEditor() - -@customElement('my-editor') -export class MyEditor extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-block-handle/tsconfig.json b/lit-block-handle/tsconfig.json deleted file mode 100644 index f3ad657d5f..0000000000 --- a/lit-block-handle/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "es2023", - "experimentalDecorators": true, - "useDefineForClassFields": false, - "module": "esnext", - "lib": ["ES2023", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/lit-block-handle/vite.config.ts b/lit-block-handle/vite.config.ts deleted file mode 100644 index fb0cdf00b5..0000000000 --- a/lit-block-handle/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [tailwindcss()], -}) diff --git a/lit-code-block/.gitignore b/lit-code-block/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/lit-code-block/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/lit-code-block/README.md b/lit-code-block/README.md deleted file mode 100644 index 33cd50e77b..0000000000 --- a/lit-code-block/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# lit-code-block - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-code-block) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-code-block) - -Run the example locally with: - -```bash -npx degit prosekit/examples/lit-code-block lit-code-block -cd lit-code-block -npm install -npm run dev -``` diff --git a/lit-code-block/index.html b/lit-code-block/index.html deleted file mode 100644 index 9637b16269..0000000000 --- a/lit-code-block/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - ProseKit + Lit - - - - - - - diff --git a/lit-code-block/package.json b/lit-code-block/package.json deleted file mode 100644 index 6e560b72f8..0000000000 --- a/lit-code-block/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "example-lit-code-block", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "@lit/context": "^1.1.6", - "lit": "^3.3.2", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/lit-code-block/src/app.css b/lit-code-block/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/lit-code-block/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/lit-code-block/src/app.ts b/lit-code-block/src/app.ts deleted file mode 100644 index 3cbf14f94d..0000000000 --- a/lit-code-block/src/app.ts +++ /dev/null @@ -1,18 +0,0 @@ -import './app.css' -import './editor' - -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -@customElement('my-app') -export class MyApp extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-code-block/src/components/editor/examples/code-block/editor.ts b/lit-code-block/src/components/editor/examples/code-block/editor.ts deleted file mode 100644 index b7b768ffbe..0000000000 --- a/lit-code-block/src/components/editor/examples/code-block/editor.ts +++ /dev/null @@ -1,87 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { ContextProvider } from '@lit/context' -import { - html, - LitElement, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import { createRef, ref, type Ref } from 'lit/directives/ref.js' -import type { Editor } from 'prosekit/core' -import { createEditor } from 'prosekit/core' - -import { sampleContent } from '../../sample/sample-doc-code-block' -import { sampleUploader } from '../../sample/sample-uploader' -import { editorContext } from '../../ui/editor-context' -import { registerLitEditorToolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export class LitEditor extends LitElement { - static override properties = { - editor: { - state: true, - attribute: false, - } satisfies PropertyDeclaration, - } - - private editor: Editor - private ref: Ref - - constructor() { - super() - - const extension = defineExtension() - this.editor = createEditor({ extension, defaultContent: sampleContent }) - this.ref = createRef() - new ContextProvider(this, { - context: editorContext, - initialValue: this.editor, - }) - } - - override createRenderRoot() { - return this - } - - override disconnectedCallback() { - this.editor.unmount() - super.disconnectedCallback() - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.editor.mount(this.ref.value) - } - - override render() { - return html` -
- -
-
-
-
- ` - } -} - -export function registerLitEditor() { - registerLitEditorToolbar() - - if (customElements.get('lit-editor-example-code-block')) return - customElements.define('lit-editor-example-code-block', LitEditor) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-example-code-block': LitEditor - } -} diff --git a/lit-code-block/src/components/editor/examples/code-block/extension.ts b/lit-code-block/src/components/editor/examples/code-block/extension.ts deleted file mode 100644 index 099cacf03b..0000000000 --- a/lit-code-block/src/components/editor/examples/code-block/extension.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { - defineCodeBlock, - defineCodeBlockShiki, -} from 'prosekit/extensions/code-block' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCodeBlock(), - defineCodeBlockShiki(), - defineCodeBlockView(), - ) -} - -export type EditorExtension = ReturnType diff --git a/lit-code-block/src/components/editor/examples/code-block/index.ts b/lit-code-block/src/components/editor/examples/code-block/index.ts deleted file mode 100644 index 9eeecbbc50..0000000000 --- a/lit-code-block/src/components/editor/examples/code-block/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-code-block/src/components/editor/sample/sample-doc-code-block.ts b/lit-code-block/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/lit-code-block/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/lit-code-block/src/components/editor/sample/sample-uploader.ts b/lit-code-block/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/lit-code-block/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/lit-code-block/src/components/editor/ui/button/button.ts b/lit-code-block/src/components/editor/ui/button/button.ts deleted file mode 100644 index aef47e4e1f..0000000000 --- a/lit-code-block/src/components/editor/ui/button/button.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { html, LitElement, nothing, type PropertyDeclaration } from 'lit' -import { - registerTooltipPopupElement, - registerTooltipPositionerElement, - registerTooltipRootElement, - registerTooltipTriggerElement, -} from 'prosekit/lit/tooltip' - -class LitButton extends LitElement { - static override properties = { - pressed: { type: Boolean }, - disabled: { type: Boolean }, - tooltip: { type: String }, - icon: { type: String }, - } satisfies Record - - pressed = false - disabled = false - tooltip = '' - icon = '' - - override createRenderRoot() { - return this - } - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - } - - private handleMouseDown = (event: MouseEvent) => { - // Prevent the editor from being blurred when the button is clicked - event.preventDefault() - } - - override render() { - const tooltip = this.tooltip - - return html` - - - - - ${tooltip - ? html` - - - ${tooltip} - - - ` - : nothing} - - ` - } -} - -export function registerLitEditorButton() { - registerTooltipPopupElement() - registerTooltipPositionerElement() - registerTooltipRootElement() - registerTooltipTriggerElement() - - if (customElements.get('lit-editor-button')) return - customElements.define('lit-editor-button', LitButton) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-button': LitButton - } -} diff --git a/lit-code-block/src/components/editor/ui/button/index.ts b/lit-code-block/src/components/editor/ui/button/index.ts deleted file mode 100644 index 02efbeadd2..0000000000 --- a/lit-code-block/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorButton } from './button' diff --git a/lit-code-block/src/components/editor/ui/code-block-view/code-block-view.ts b/lit-code-block/src/components/editor/ui/code-block-view/code-block-view.ts deleted file mode 100644 index ce30a8fd93..0000000000 --- a/lit-code-block/src/components/editor/ui/code-block-view/code-block-view.ts +++ /dev/null @@ -1,106 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineNodeView } from 'prosekit/core' -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { ProseMirrorNode } from 'prosekit/pm/model' -import type { EditorView } from 'prosekit/pm/view' - -class CodeBlockNodeView { - dom: HTMLElement - contentDOM: HTMLElement - private node: ProseMirrorNode - private view: EditorView - private getPos: () => number | undefined - private select: HTMLSelectElement - private pre: HTMLPreElement - - constructor( - node: ProseMirrorNode, - view: EditorView, - getPos: () => number | undefined, - ) { - this.node = node - this.view = view - this.getPos = getPos - - const root = document.createElement('div') - root.setAttribute('data-node-view-root', 'true') - - const wrapper = document.createElement('div') - wrapper.className = - 'relative mx-2 top-3 h-0 select-none overflow-visible text-xs' - wrapper.setAttribute('contenteditable', 'false') - - this.select = document.createElement('select') - this.select.setAttribute('aria-label', 'Code block language') - this.select.className = - 'outline-unset focus:outline-unset relative box-border w-auto cursor-pointer select-none appearance-none rounded-sm border-none bg-transparent px-2 py-1 text-xs transition text-(--prosemirror-highlight) opacity-0 hover:opacity-80 [div[data-node-view-root]:hover_&]:opacity-50 hover:[div[data-node-view-root]:hover_&]:opacity-80' - - const plain = document.createElement('option') - plain.value = '' - plain.textContent = 'Plain Text' - this.select.appendChild(plain) - - for (const info of shikiBundledLanguagesInfo) { - const option = document.createElement('option') - option.value = info.id - option.textContent = info.name - this.select.appendChild(option) - } - - this.select.addEventListener('change', this.handleChange) - wrapper.appendChild(this.select) - - this.pre = document.createElement('pre') - this.contentDOM = document.createElement('code') - this.contentDOM.setAttribute('data-node-view-content', 'true') - this.contentDOM.style.whiteSpace = 'inherit' - this.pre.appendChild(this.contentDOM) - - root.appendChild(wrapper) - root.appendChild(this.pre) - - this.dom = root - this.syncAttrs() - } - - private handleChange = (event: Event) => { - const language = (event.target as HTMLSelectElement).value - const pos = this.getPos() - if (typeof pos !== 'number') return - const attrs: CodeBlockAttrs = { - ...(this.node.attrs as CodeBlockAttrs), - language, - } - this.view.dispatch(this.view.state.tr.setNodeMarkup(pos, undefined, attrs)) - } - - private syncAttrs() { - const language = (this.node.attrs as CodeBlockAttrs).language || '' - this.select.value = language - if (language) { - this.pre.setAttribute('data-language', language) - } else { - this.pre.removeAttribute('data-language') - } - } - - update(node: ProseMirrorNode) { - if (node.type !== this.node.type) return false - this.node = node - this.syncAttrs() - return true - } - - destroy() { - this.select.removeEventListener('change', this.handleChange) - } -} - -export function defineCodeBlockView(): Extension { - return defineNodeView({ - name: 'codeBlock', - constructor: (node, view, getPos) => - new CodeBlockNodeView(node, view, getPos), - }) -} diff --git a/lit-code-block/src/components/editor/ui/code-block-view/index.ts b/lit-code-block/src/components/editor/ui/code-block-view/index.ts deleted file mode 100644 index a96ff094eb..0000000000 --- a/lit-code-block/src/components/editor/ui/code-block-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { defineCodeBlockView } from './code-block-view' diff --git a/lit-code-block/src/components/editor/ui/editor-context.ts b/lit-code-block/src/components/editor/ui/editor-context.ts deleted file mode 100644 index 7af6d3a865..0000000000 --- a/lit-code-block/src/components/editor/ui/editor-context.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createContext } from '@lit/context' -import type { Editor } from 'prosekit/core' - -export const editorContext = createContext( - 'prosekit-editor', -) diff --git a/lit-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.ts b/lit-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.ts deleted file mode 100644 index 3a129e53de..0000000000 --- a/lit-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { html, LitElement, nothing, type PropertyDeclaration } from 'lit' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { - registerPopoverPopupElement, - registerPopoverPositionerElement, - registerPopoverRootElement, - registerPopoverTriggerElement, - type OpenChangeEvent, -} from 'prosekit/lit/popover' - -import { registerLitEditorButton } from '../button' - -let imageUploadId = 0 - -class LitImageUploadPopover extends LitElement { - static override properties = { - editor: { attribute: false } satisfies PropertyDeclaration, - uploader: { attribute: false } satisfies PropertyDeclaration< - Uploader - >, - tooltip: { type: String }, - disabled: { type: Boolean }, - icon: { type: String }, - } - - editor?: Editor - uploader?: Uploader - tooltip = '' - disabled = false - icon = '' - - private open = false - private url = '' - private file: File | null = null - private ariaId = `lit-image-upload-${imageUploadId++}` - - override createRenderRoot() { - return this - } - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - } - - private handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - this.deferResetState() - } - - this.open = event.detail - this.requestUpdate() - } - - private handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - this.file = selectedFile - this.url = '' - } else { - this.file = null - } - - this.requestUpdate() - } - - private handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - this.url = inputUrl - this.file = null - } else { - this.url = '' - } - - this.requestUpdate() - } - - private deferResetState() { - setTimeout(() => { - this.url = '' - this.file = null - this.requestUpdate() - }, 300) - } - - private handleSubmit = () => { - const editor = this.editor - if (!editor) return - - if (this.url) { - editor.commands.insertImage({ src: this.url }) - } else if (this.file && this.uploader) { - editor.commands.uploadImage({ file: this.file, uploader: this.uploader }) - } - - this.open = false - this.deferResetState() - this.requestUpdate() - } - - override render() { - return html` - - - - - - - - ${!this.file - ? html` - - - ` - : nothing} - ${!this.url - ? html` - - - ` - : nothing} - ${this.url - ? html` - - ` - : nothing} - ${this.file - ? html` - - ` - : nothing} - - - - ` - } -} - -export function registerLitEditorImageUploadPopover() { - registerLitEditorButton() - registerPopoverPopupElement() - registerPopoverPositionerElement() - registerPopoverRootElement() - registerPopoverTriggerElement() - - if (customElements.get('lit-editor-image-upload-popover')) return - customElements.define( - 'lit-editor-image-upload-popover', - LitImageUploadPopover, - ) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-image-upload-popover': LitImageUploadPopover - } -} diff --git a/lit-code-block/src/components/editor/ui/image-upload-popover/index.ts b/lit-code-block/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ff00f20c86..0000000000 --- a/lit-code-block/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorImageUploadPopover } from './image-upload-popover' diff --git a/lit-code-block/src/components/editor/ui/toolbar/index.ts b/lit-code-block/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 6d6df28ea4..0000000000 --- a/lit-code-block/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorToolbar } from './toolbar' diff --git a/lit-code-block/src/components/editor/ui/toolbar/toolbar.ts b/lit-code-block/src/components/editor/ui/toolbar/toolbar.ts deleted file mode 100644 index ee46ea40a1..0000000000 --- a/lit-code-block/src/components/editor/ui/toolbar/toolbar.ts +++ /dev/null @@ -1,467 +0,0 @@ -import { ContextConsumer } from '@lit/context' -import { - html, - LitElement, - nothing, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import type { BasicExtension } from 'prosekit/basic' -import { defineUpdateHandler, type Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' - -import { registerLitEditorButton } from '../button' -import { editorContext } from '../editor-context' -import { registerLitEditorImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -class LitToolbar extends LitElement { - static override properties = { - uploader: { attribute: false } satisfies PropertyDeclaration< - Uploader - >, - } - - uploader?: Uploader - - private editorConsumer = new ContextConsumer(this, { - context: editorContext, - subscribe: true, - }) - - private removeUpdateExtension?: VoidFunction - - override createRenderRoot() { - return this - } - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - this.attachEditorListener() - } - - override disconnectedCallback() { - this.detachEditorListener() - super.disconnectedCallback() - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.attachEditorListener() - } - - private attachEditorListener() { - this.detachEditorListener() - - const editor = this.editorConsumer.value - if (!editor) return - - this.removeUpdateExtension = editor.use( - defineUpdateHandler(() => this.requestUpdate()), - ) - } - - private detachEditorListener() { - this.removeUpdateExtension?.() - this.removeUpdateExtension = undefined - } - - override render() { - const editor = this.editorConsumer.value as - | Editor - | undefined - if (!editor) { - return nothing - } - - const items = getToolbarItems(editor) - - return html` -
- ${items.undo - ? html` - - ` - : nothing} - ${items.redo - ? html` - - ` - : nothing} - ${items.bold - ? html` - - ` - : nothing} - ${items.italic - ? html` - - ` - : nothing} - ${items.underline - ? html` - - ` - : nothing} - ${items.strike - ? html` - - ` - : nothing} - ${items.code - ? html` - - ` - : nothing} - ${items.codeBlock - ? html` - - ` - : nothing} - ${items.heading1 - ? html` - - ` - : nothing} - ${items.heading2 - ? html` - - ` - : nothing} - ${items.heading3 - ? html` - - ` - : nothing} - ${items.horizontalRule - ? html` - - ` - : nothing} - ${items.blockquote - ? html` - - ` - : nothing} - ${items.bulletList - ? html` - - ` - : nothing} - ${items.orderedList - ? html` - - ` - : nothing} - ${items.taskList - ? html` - - ` - : nothing} - ${items.toggleList - ? html` - - ` - : nothing} - ${items.indentList - ? html` - - ` - : nothing} - ${items.dedentList - ? html` - - ` - : nothing} - ${this.uploader && items.insertImage - ? html` - - ` - : nothing} -
- ` - } -} - -export function registerLitEditorToolbar() { - registerLitEditorButton() - registerLitEditorImageUploadPopover() - - if (customElements.get('lit-editor-toolbar')) return - customElements.define('lit-editor-toolbar', LitToolbar) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-toolbar': LitToolbar - } -} diff --git a/lit-code-block/src/editor.ts b/lit-code-block/src/editor.ts deleted file mode 100644 index 95412c3a91..0000000000 --- a/lit-code-block/src/editor.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { registerLitEditor } from './components/editor/examples/code-block' -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -registerLitEditor() - -@customElement('my-editor') -export class MyEditor extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-code-block/tsconfig.json b/lit-code-block/tsconfig.json deleted file mode 100644 index f3ad657d5f..0000000000 --- a/lit-code-block/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "es2023", - "experimentalDecorators": true, - "useDefineForClassFields": false, - "module": "esnext", - "lib": ["ES2023", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/lit-code-block/vite.config.ts b/lit-code-block/vite.config.ts deleted file mode 100644 index fb0cdf00b5..0000000000 --- a/lit-code-block/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [tailwindcss()], -}) diff --git a/lit-minimal/.gitignore b/lit-minimal/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/lit-minimal/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/lit-minimal/README.md b/lit-minimal/README.md deleted file mode 100644 index 954cc8c15d..0000000000 --- a/lit-minimal/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# lit-minimal - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-minimal) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-minimal) - -Run the example locally with: - -```bash -npx degit prosekit/examples/lit-minimal lit-minimal -cd lit-minimal -npm install -npm run dev -``` diff --git a/lit-minimal/index.html b/lit-minimal/index.html deleted file mode 100644 index 9637b16269..0000000000 --- a/lit-minimal/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - ProseKit + Lit - - - - - - - diff --git a/lit-minimal/package.json b/lit-minimal/package.json deleted file mode 100644 index 682411fbd7..0000000000 --- a/lit-minimal/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "example-lit-minimal", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "lit": "^3.3.2", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "postcss": "^8.5.14", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/lit-minimal/src/app.css b/lit-minimal/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/lit-minimal/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/lit-minimal/src/app.ts b/lit-minimal/src/app.ts deleted file mode 100644 index 3cbf14f94d..0000000000 --- a/lit-minimal/src/app.ts +++ /dev/null @@ -1,18 +0,0 @@ -import './app.css' -import './editor' - -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -@customElement('my-app') -export class MyApp extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-minimal/src/components/editor/examples/minimal/editor.ts b/lit-minimal/src/components/editor/examples/minimal/editor.ts deleted file mode 100644 index 5603677c48..0000000000 --- a/lit-minimal/src/components/editor/examples/minimal/editor.ts +++ /dev/null @@ -1,64 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { - html, - LitElement, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import { createRef, ref, type Ref } from 'lit/directives/ref.js' -import { defineBasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import { createEditor } from 'prosekit/core' - -export class LitEditor extends LitElement { - static override properties = { - editor: { - state: true, - attribute: false, - } satisfies PropertyDeclaration, - } - - private editor: Editor - private ref: Ref - - constructor() { - super() - - const extension = defineBasicExtension() - this.editor = createEditor({ extension }) - this.ref = createRef() - } - - override createRenderRoot() { - return this - } - - override disconnectedCallback() { - this.editor.unmount() - super.disconnectedCallback() - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.editor.mount(this.ref.value) - } - - override render() { - return html` -
- ` - } -} - -export function registerLitEditor() { - if (customElements.get('lit-editor-example-minimal')) return - customElements.define('lit-editor-example-minimal', LitEditor) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-example-minimal': LitEditor - } -} diff --git a/lit-minimal/src/components/editor/examples/minimal/index.ts b/lit-minimal/src/components/editor/examples/minimal/index.ts deleted file mode 100644 index 9eeecbbc50..0000000000 --- a/lit-minimal/src/components/editor/examples/minimal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-minimal/src/editor.ts b/lit-minimal/src/editor.ts deleted file mode 100644 index 63bc2902d8..0000000000 --- a/lit-minimal/src/editor.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { registerLitEditor } from './components/editor/examples/minimal' -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -registerLitEditor() - -@customElement('my-editor') -export class MyEditor extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-minimal/tsconfig.json b/lit-minimal/tsconfig.json deleted file mode 100644 index f3ad657d5f..0000000000 --- a/lit-minimal/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "es2023", - "experimentalDecorators": true, - "useDefineForClassFields": false, - "module": "esnext", - "lib": ["ES2023", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/lit-minimal/vite.config.ts b/lit-minimal/vite.config.ts deleted file mode 100644 index fb0cdf00b5..0000000000 --- a/lit-minimal/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [tailwindcss()], -}) diff --git a/lit-slash-menu/.gitignore b/lit-slash-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/lit-slash-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/lit-slash-menu/README.md b/lit-slash-menu/README.md deleted file mode 100644 index 1a4d660037..0000000000 --- a/lit-slash-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# lit-slash-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-slash-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-slash-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/lit-slash-menu lit-slash-menu -cd lit-slash-menu -npm install -npm run dev -``` diff --git a/lit-slash-menu/index.html b/lit-slash-menu/index.html deleted file mode 100644 index 9637b16269..0000000000 --- a/lit-slash-menu/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - ProseKit + Lit - - - - - - - diff --git a/lit-slash-menu/package.json b/lit-slash-menu/package.json deleted file mode 100644 index 471db92b24..0000000000 --- a/lit-slash-menu/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-lit-slash-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "@lit/context": "^1.1.6", - "lit": "^3.3.2", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "postcss": "^8.5.14", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/lit-slash-menu/src/app.css b/lit-slash-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/lit-slash-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/lit-slash-menu/src/app.ts b/lit-slash-menu/src/app.ts deleted file mode 100644 index 3cbf14f94d..0000000000 --- a/lit-slash-menu/src/app.ts +++ /dev/null @@ -1,18 +0,0 @@ -import './app.css' -import './editor' - -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -@customElement('my-app') -export class MyApp extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-slash-menu/src/components/editor/examples/slash-menu/editor.ts b/lit-slash-menu/src/components/editor/examples/slash-menu/editor.ts deleted file mode 100644 index 10cbfbd1e1..0000000000 --- a/lit-slash-menu/src/components/editor/examples/slash-menu/editor.ts +++ /dev/null @@ -1,86 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { ContextProvider } from '@lit/context' -import { - html, - LitElement, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import { createRef, ref, type Ref } from 'lit/directives/ref.js' -import type { Editor } from 'prosekit/core' -import { createEditor } from 'prosekit/core' - -import { editorContext } from '../../ui/editor-context' -import { registerLitEditorSlashMenu } from '../../ui/slash-menu' - -import { defineExtension } from './extension' - -export class LitEditor extends LitElement { - static override properties = { - editor: { - state: true, - attribute: false, - } satisfies PropertyDeclaration, - } - - private editor: Editor - private ref: Ref - constructor() { - super() - - const extension = defineExtension() - this.editor = createEditor({ extension }) - this.ref = createRef() - new ContextProvider(this, { - context: editorContext, - initialValue: this.editor, - }) - } - - override createRenderRoot() { - return this - } - - override disconnectedCallback() { - this.editor.unmount() - super.disconnectedCallback() - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.editor.mount(this.ref.value) - } - - override render() { - return html` -
-
-
- -
-
- ` - } -} - -export function registerLitEditor() { - registerLitEditorSlashMenu() - - if (customElements.get('lit-editor-example-slash-menu')) return - customElements.define('lit-editor-example-slash-menu', LitEditor) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-example-slash-menu': LitEditor - } -} diff --git a/lit-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/lit-slash-menu/src/components/editor/examples/slash-menu/extension.ts deleted file mode 100644 index 0edda60136..0000000000 --- a/lit-slash-menu/src/components/editor/examples/slash-menu/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/lit-slash-menu/src/components/editor/examples/slash-menu/index.ts b/lit-slash-menu/src/components/editor/examples/slash-menu/index.ts deleted file mode 100644 index 9eeecbbc50..0000000000 --- a/lit-slash-menu/src/components/editor/examples/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-slash-menu/src/components/editor/ui/editor-context.ts b/lit-slash-menu/src/components/editor/ui/editor-context.ts deleted file mode 100644 index 7af6d3a865..0000000000 --- a/lit-slash-menu/src/components/editor/ui/editor-context.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createContext } from '@lit/context' -import type { Editor } from 'prosekit/core' - -export const editorContext = createContext( - 'prosekit-editor', -) diff --git a/lit-slash-menu/src/components/editor/ui/slash-menu/index.ts b/lit-slash-menu/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 9f49d0de7f..0000000000 --- a/lit-slash-menu/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorSlashMenu } from './slash-menu' diff --git a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts deleted file mode 100644 index f2e0d5318d..0000000000 --- a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { html, LitElement } from 'lit' - -export class SlashMenuEmptyElement extends LitElement { - override createRenderRoot() { - return this - } - - override render() { - return html` - - No results - - ` - } -} diff --git a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts deleted file mode 100644 index ad7bd23cf7..0000000000 --- a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { html, LitElement } from 'lit' - -export class SlashMenuItemElement extends LitElement { - static override properties = { - label: { type: String }, - kbd: { type: String }, - } - - label: string - kbd: string - - constructor() { - super() - this.label = '' - this.kbd = '' - } - - override createRenderRoot() { - return this - } - - // TODO: maybe this should changed to valueChange event?? - handleSelect = () => { - this.dispatchEvent(new CustomEvent('select')) - } - - override render() { - return html` - - ${this.label} - ${this.kbd - ? html` - - ${this.kbd} - - ` - : ''} - - ` - } -} diff --git a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts deleted file mode 100644 index 5b0eedb85d..0000000000 --- a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { ContextConsumer } from '@lit/context' -import { html, LitElement } from 'lit' -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import { canUseRegexLookbehind } from 'prosekit/core' -import { - registerAutocompleteEmptyElement, - registerAutocompleteItemElement, - registerAutocompletePopupElement, - registerAutocompletePositionerElement, - registerAutocompleteRootElement, -} from 'prosekit/lit/autocomplete' - -import { editorContext } from '../editor-context' - -import { SlashMenuEmptyElement } from './slash-menu-empty' -import { SlashMenuItemElement } from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(? - | undefined - if (!editor) { - return html`` - } - - return html` - - - -
- editor.commands.setParagraph()} - > - editor.commands.setHeading({ level: 1 })} - > - editor.commands.setHeading({ level: 2 })} - > - editor.commands.setHeading({ level: 3 })} - > - editor.commands.wrapInList({ kind: 'bullet' })} - > - editor.commands.wrapInList({ kind: 'ordered' })} - > - editor.commands.wrapInList({ kind: 'task' })} - > - editor.commands.wrapInList({ kind: 'toggle' })} - > - editor.commands.setBlockquote()} - > - editor.commands.insertTable({ row: 3, col: 3 })} - > - editor.commands.insertHorizontalRule()} - > - editor.commands.setCodeBlock()} - > - -
-
-
-
- ` - } -} - -export function registerLitEditorSlashMenu() { - registerAutocompleteEmptyElement() - registerAutocompleteItemElement() - registerAutocompletePopupElement() - registerAutocompletePositionerElement() - registerAutocompleteRootElement() - - if (!customElements.get('lit-editor-slash-menu-item')) { - customElements.define('lit-editor-slash-menu-item', SlashMenuItemElement) - } - if (!customElements.get('lit-editor-slash-menu-empty')) { - customElements.define('lit-editor-slash-menu-empty', SlashMenuEmptyElement) - } - if (customElements.get('lit-editor-slash-menu')) return - customElements.define('lit-editor-slash-menu', SlashMenuElement) -} diff --git a/lit-slash-menu/src/editor.ts b/lit-slash-menu/src/editor.ts deleted file mode 100644 index 7ea7548ab0..0000000000 --- a/lit-slash-menu/src/editor.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { registerLitEditor } from './components/editor/examples/slash-menu' -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -registerLitEditor() - -@customElement('my-editor') -export class MyEditor extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-slash-menu/tsconfig.json b/lit-slash-menu/tsconfig.json deleted file mode 100644 index f3ad657d5f..0000000000 --- a/lit-slash-menu/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "es2023", - "experimentalDecorators": true, - "useDefineForClassFields": false, - "module": "esnext", - "lib": ["ES2023", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/lit-slash-menu/vite.config.ts b/lit-slash-menu/vite.config.ts deleted file mode 100644 index fb0cdf00b5..0000000000 --- a/lit-slash-menu/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [tailwindcss()], -}) diff --git a/lit-table/.gitignore b/lit-table/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/lit-table/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/lit-table/README.md b/lit-table/README.md deleted file mode 100644 index 72d736d130..0000000000 --- a/lit-table/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# lit-table - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-table) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-table) - -Run the example locally with: - -```bash -npx degit prosekit/examples/lit-table lit-table -cd lit-table -npm install -npm run dev -``` diff --git a/lit-table/index.html b/lit-table/index.html deleted file mode 100644 index 9637b16269..0000000000 --- a/lit-table/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - ProseKit + Lit - - - - - - - diff --git a/lit-table/package.json b/lit-table/package.json deleted file mode 100644 index 4546c68003..0000000000 --- a/lit-table/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-lit-table", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "@lit/context": "^1.1.6", - "lit": "^3.3.2", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "postcss": "^8.5.14", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/lit-table/src/app.css b/lit-table/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/lit-table/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/lit-table/src/app.ts b/lit-table/src/app.ts deleted file mode 100644 index 3cbf14f94d..0000000000 --- a/lit-table/src/app.ts +++ /dev/null @@ -1,18 +0,0 @@ -import './app.css' -import './editor' - -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -@customElement('my-app') -export class MyApp extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-table/src/components/editor/examples/table/editor.ts b/lit-table/src/components/editor/examples/table/editor.ts deleted file mode 100644 index 3b3f30c393..0000000000 --- a/lit-table/src/components/editor/examples/table/editor.ts +++ /dev/null @@ -1,96 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { ContextProvider } from '@lit/context' -import { - html, - LitElement, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import { createRef, ref, type Ref } from 'lit/directives/ref.js' -import type { Editor, NodeJSON } from 'prosekit/core' -import { createEditor } from 'prosekit/core' - -import { sampleContent } from '../../sample/sample-doc-table' -import { editorContext } from '../../ui/editor-context' -import { registerLitEditorTableHandle } from '../../ui/table-handle' - -import { defineExtension } from './extension' - -export class LitEditor extends LitElement { - static override properties = { - initialContent: { attribute: false } satisfies PropertyDeclaration< - NodeJSON | undefined - >, - } - - initialContent?: NodeJSON - - private editor?: Editor - private ref: Ref - - constructor() { - super() - this.ref = createRef() - } - - override createRenderRoot() { - return this - } - - override disconnectedCallback() { - this.editor?.unmount() - super.disconnectedCallback() - } - - override willUpdate() { - if (this.editor) { - return - } - - const extension = defineExtension() - this.editor = createEditor({ - extension, - defaultContent: this.initialContent ?? sampleContent, - }) - new ContextProvider(this, { - context: editorContext, - initialValue: this.editor, - }) - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.editor?.mount(this.ref.value) - } - - override render() { - return html` -
-
-
- -
-
- ` - } -} - -export function registerLitEditor() { - registerLitEditorTableHandle() - - if (customElements.get('lit-editor-example-table')) return - customElements.define('lit-editor-example-table', LitEditor) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-example-table': LitEditor - } -} diff --git a/lit-table/src/components/editor/examples/table/extension.ts b/lit-table/src/components/editor/examples/table/extension.ts deleted file mode 100644 index ee7b142041..0000000000 --- a/lit-table/src/components/editor/examples/table/extension.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineTable(), - defineHistory(), - defineGapCursor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/lit-table/src/components/editor/examples/table/index.ts b/lit-table/src/components/editor/examples/table/index.ts deleted file mode 100644 index 9eeecbbc50..0000000000 --- a/lit-table/src/components/editor/examples/table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-table/src/components/editor/sample/sample-doc-table.ts b/lit-table/src/components/editor/sample/sample-doc-table.ts deleted file mode 100644 index c737121672..0000000000 --- a/lit-table/src/components/editor/sample/sample-doc-table.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D1', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D2', - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], -} diff --git a/lit-table/src/components/editor/ui/editor-context.ts b/lit-table/src/components/editor/ui/editor-context.ts deleted file mode 100644 index 7af6d3a865..0000000000 --- a/lit-table/src/components/editor/ui/editor-context.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createContext } from '@lit/context' -import type { Editor } from 'prosekit/core' - -export const editorContext = createContext( - 'prosekit-editor', -) diff --git a/lit-table/src/components/editor/ui/table-handle/index.ts b/lit-table/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 0b0e06268e..0000000000 --- a/lit-table/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorTableHandle } from './table-handle' diff --git a/lit-table/src/components/editor/ui/table-handle/table-handle.ts b/lit-table/src/components/editor/ui/table-handle/table-handle.ts deleted file mode 100644 index b240b86e24..0000000000 --- a/lit-table/src/components/editor/ui/table-handle/table-handle.ts +++ /dev/null @@ -1,335 +0,0 @@ -import { ContextConsumer } from '@lit/context' -import { - html, - LitElement, - nothing, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import type { Editor } from 'prosekit/core' -import { defineUpdateHandler } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { - registerMenuItemElement, - registerMenuPopupElement, - registerMenuPositionerElement, -} from 'prosekit/lit/menu' -import { - registerTableHandleColumnMenuRootElement, - registerTableHandleColumnMenuTriggerElement, - registerTableHandleColumnPopupElement, - registerTableHandleColumnPositionerElement, - registerTableHandleDragPreviewElement, - registerTableHandleDropIndicatorElement, - registerTableHandleRootElement, - registerTableHandleRowMenuRootElement, - registerTableHandleRowMenuTriggerElement, - registerTableHandleRowPopupElement, - registerTableHandleRowPositionerElement, -} from 'prosekit/lit/table-handle' - -import { editorContext } from '../editor-context' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -class LitTableHandle extends LitElement { - static override properties = { - dir: { type: String } satisfies PropertyDeclaration<'ltr' | 'rtl'>, - } - - override dir: string = '' - - private editorConsumer = new ContextConsumer(this, { - context: editorContext, - subscribe: true, - }) - - private removeUpdateExtension?: VoidFunction - - override createRenderRoot() { - return this - } - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - this.attachEditorListener() - } - - override disconnectedCallback() { - this.detachEditorListener() - super.disconnectedCallback() - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.attachEditorListener() - } - - private attachEditorListener() { - this.detachEditorListener() - - const editor = this.editorConsumer.value - if (!editor) return - - this.removeUpdateExtension = editor.use( - defineUpdateHandler(() => this.requestUpdate()), - ) - } - - private detachEditorListener() { - this.removeUpdateExtension?.() - this.removeUpdateExtension = undefined - } - - override render() { - const editor = this.editorConsumer.value as - | Editor - | undefined - if (!editor) { - return nothing - } - - const state = getTableHandleState(editor) - const placement = this.dir === 'rtl' ? 'right' : 'left' - - return html` - - - - - - - -
-
- - - ${state.addTableColumnBefore.canExec - ? html` - - Insert Left - - ` - : nothing} - ${state.addTableColumnAfter.canExec - ? html` - - Insert Right - - ` - : nothing} - ${state.deleteCellSelection.canExec - ? html` - - Clear Contents - - Del - - - ` - : nothing} - ${state.deleteTableColumn.canExec - ? html` - - Delete Column - - ` - : nothing} - ${state.deleteTable.canExec - ? html` - - Delete Table - - ` - : nothing} - - -
-
-
- - - - -
-
- - - ${state.addTableRowAbove.canExec - ? html` - - Insert Above - - ` - : nothing} - ${state.addTableRowBelow.canExec - ? html` - - Insert Below - - ` - : nothing} - ${state.deleteCellSelection.canExec - ? html` - - Clear Contents - - Del - - - ` - : nothing} - ${state.deleteTableRow.canExec - ? html` - - Delete Row - - ` - : nothing} - ${state.deleteTable.canExec - ? html` - - Delete Table - - ` - : nothing} - - -
-
-
-
- ` - } -} - -export function registerLitEditorTableHandle() { - registerMenuItemElement() - registerMenuPopupElement() - registerMenuPositionerElement() - registerTableHandleColumnMenuRootElement() - registerTableHandleColumnMenuTriggerElement() - registerTableHandleColumnPopupElement() - registerTableHandleColumnPositionerElement() - registerTableHandleDragPreviewElement() - registerTableHandleDropIndicatorElement() - registerTableHandleRootElement() - registerTableHandleRowMenuRootElement() - registerTableHandleRowMenuTriggerElement() - registerTableHandleRowPopupElement() - registerTableHandleRowPositionerElement() - - if (customElements.get('lit-editor-table-handle')) return - customElements.define('lit-editor-table-handle', LitTableHandle) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-table-handle': LitTableHandle - } -} diff --git a/lit-table/src/editor.ts b/lit-table/src/editor.ts deleted file mode 100644 index 8ca4bad3e5..0000000000 --- a/lit-table/src/editor.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { registerLitEditor } from './components/editor/examples/table' -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -registerLitEditor() - -@customElement('my-editor') -export class MyEditor extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-table/tsconfig.json b/lit-table/tsconfig.json deleted file mode 100644 index f3ad657d5f..0000000000 --- a/lit-table/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "es2023", - "experimentalDecorators": true, - "useDefineForClassFields": false, - "module": "esnext", - "lib": ["ES2023", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/lit-table/vite.config.ts b/lit-table/vite.config.ts deleted file mode 100644 index fb0cdf00b5..0000000000 --- a/lit-table/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [tailwindcss()], -}) diff --git a/lit-toolbar/.gitignore b/lit-toolbar/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/lit-toolbar/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/lit-toolbar/README.md b/lit-toolbar/README.md deleted file mode 100644 index 6f77188cb3..0000000000 --- a/lit-toolbar/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# lit-toolbar - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-toolbar) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-toolbar) - -Run the example locally with: - -```bash -npx degit prosekit/examples/lit-toolbar lit-toolbar -cd lit-toolbar -npm install -npm run dev -``` diff --git a/lit-toolbar/index.html b/lit-toolbar/index.html deleted file mode 100644 index 9637b16269..0000000000 --- a/lit-toolbar/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - ProseKit + Lit - - - - - - - diff --git a/lit-toolbar/package.json b/lit-toolbar/package.json deleted file mode 100644 index cd0f850d13..0000000000 --- a/lit-toolbar/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-lit-toolbar", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "@lit/context": "^1.1.6", - "lit": "^3.3.2", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "postcss": "^8.5.14", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/lit-toolbar/src/app.css b/lit-toolbar/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/lit-toolbar/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/lit-toolbar/src/app.ts b/lit-toolbar/src/app.ts deleted file mode 100644 index 3cbf14f94d..0000000000 --- a/lit-toolbar/src/app.ts +++ /dev/null @@ -1,18 +0,0 @@ -import './app.css' -import './editor' - -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -@customElement('my-app') -export class MyApp extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-toolbar/src/components/editor/examples/toolbar/editor.ts b/lit-toolbar/src/components/editor/examples/toolbar/editor.ts deleted file mode 100644 index 5991536124..0000000000 --- a/lit-toolbar/src/components/editor/examples/toolbar/editor.ts +++ /dev/null @@ -1,85 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { ContextProvider } from '@lit/context' -import { - html, - LitElement, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import { createRef, ref, type Ref } from 'lit/directives/ref.js' -import type { Editor } from 'prosekit/core' -import { createEditor } from 'prosekit/core' - -import { sampleUploader } from '../../sample/sample-uploader' -import { editorContext } from '../../ui/editor-context' -import { registerLitEditorToolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export class LitEditor extends LitElement { - static override properties = { - editor: { - state: true, - attribute: false, - } satisfies PropertyDeclaration, - } - - private editor: Editor - private ref: Ref - constructor() { - super() - - const extension = defineExtension() - this.editor = createEditor({ extension }) - this.ref = createRef() - new ContextProvider(this, { - context: editorContext, - initialValue: this.editor, - }) - } - - override createRenderRoot() { - return this - } - - override disconnectedCallback() { - this.editor.unmount() - super.disconnectedCallback() - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.editor.mount(this.ref.value) - } - - override render() { - return html` -
- -
-
-
-
- ` - } -} - -export function registerLitEditor() { - registerLitEditorToolbar() - - if (customElements.get('lit-editor-example-toolbar')) return - customElements.define('lit-editor-example-toolbar', LitEditor) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-example-toolbar': LitEditor - } -} diff --git a/lit-toolbar/src/components/editor/examples/toolbar/extension.ts b/lit-toolbar/src/components/editor/examples/toolbar/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/lit-toolbar/src/components/editor/examples/toolbar/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/lit-toolbar/src/components/editor/examples/toolbar/index.ts b/lit-toolbar/src/components/editor/examples/toolbar/index.ts deleted file mode 100644 index 9eeecbbc50..0000000000 --- a/lit-toolbar/src/components/editor/examples/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-toolbar/src/components/editor/sample/sample-uploader.ts b/lit-toolbar/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/lit-toolbar/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/lit-toolbar/src/components/editor/ui/button/button.ts b/lit-toolbar/src/components/editor/ui/button/button.ts deleted file mode 100644 index aef47e4e1f..0000000000 --- a/lit-toolbar/src/components/editor/ui/button/button.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { html, LitElement, nothing, type PropertyDeclaration } from 'lit' -import { - registerTooltipPopupElement, - registerTooltipPositionerElement, - registerTooltipRootElement, - registerTooltipTriggerElement, -} from 'prosekit/lit/tooltip' - -class LitButton extends LitElement { - static override properties = { - pressed: { type: Boolean }, - disabled: { type: Boolean }, - tooltip: { type: String }, - icon: { type: String }, - } satisfies Record - - pressed = false - disabled = false - tooltip = '' - icon = '' - - override createRenderRoot() { - return this - } - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - } - - private handleMouseDown = (event: MouseEvent) => { - // Prevent the editor from being blurred when the button is clicked - event.preventDefault() - } - - override render() { - const tooltip = this.tooltip - - return html` - - - - - ${tooltip - ? html` - - - ${tooltip} - - - ` - : nothing} - - ` - } -} - -export function registerLitEditorButton() { - registerTooltipPopupElement() - registerTooltipPositionerElement() - registerTooltipRootElement() - registerTooltipTriggerElement() - - if (customElements.get('lit-editor-button')) return - customElements.define('lit-editor-button', LitButton) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-button': LitButton - } -} diff --git a/lit-toolbar/src/components/editor/ui/button/index.ts b/lit-toolbar/src/components/editor/ui/button/index.ts deleted file mode 100644 index 02efbeadd2..0000000000 --- a/lit-toolbar/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorButton } from './button' diff --git a/lit-toolbar/src/components/editor/ui/editor-context.ts b/lit-toolbar/src/components/editor/ui/editor-context.ts deleted file mode 100644 index 7af6d3a865..0000000000 --- a/lit-toolbar/src/components/editor/ui/editor-context.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createContext } from '@lit/context' -import type { Editor } from 'prosekit/core' - -export const editorContext = createContext( - 'prosekit-editor', -) diff --git a/lit-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.ts b/lit-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.ts deleted file mode 100644 index 3a129e53de..0000000000 --- a/lit-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.ts +++ /dev/null @@ -1,200 +0,0 @@ -import { html, LitElement, nothing, type PropertyDeclaration } from 'lit' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { - registerPopoverPopupElement, - registerPopoverPositionerElement, - registerPopoverRootElement, - registerPopoverTriggerElement, - type OpenChangeEvent, -} from 'prosekit/lit/popover' - -import { registerLitEditorButton } from '../button' - -let imageUploadId = 0 - -class LitImageUploadPopover extends LitElement { - static override properties = { - editor: { attribute: false } satisfies PropertyDeclaration, - uploader: { attribute: false } satisfies PropertyDeclaration< - Uploader - >, - tooltip: { type: String }, - disabled: { type: Boolean }, - icon: { type: String }, - } - - editor?: Editor - uploader?: Uploader - tooltip = '' - disabled = false - icon = '' - - private open = false - private url = '' - private file: File | null = null - private ariaId = `lit-image-upload-${imageUploadId++}` - - override createRenderRoot() { - return this - } - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - } - - private handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - this.deferResetState() - } - - this.open = event.detail - this.requestUpdate() - } - - private handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - this.file = selectedFile - this.url = '' - } else { - this.file = null - } - - this.requestUpdate() - } - - private handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - this.url = inputUrl - this.file = null - } else { - this.url = '' - } - - this.requestUpdate() - } - - private deferResetState() { - setTimeout(() => { - this.url = '' - this.file = null - this.requestUpdate() - }, 300) - } - - private handleSubmit = () => { - const editor = this.editor - if (!editor) return - - if (this.url) { - editor.commands.insertImage({ src: this.url }) - } else if (this.file && this.uploader) { - editor.commands.uploadImage({ file: this.file, uploader: this.uploader }) - } - - this.open = false - this.deferResetState() - this.requestUpdate() - } - - override render() { - return html` - - - - - - - - ${!this.file - ? html` - - - ` - : nothing} - ${!this.url - ? html` - - - ` - : nothing} - ${this.url - ? html` - - ` - : nothing} - ${this.file - ? html` - - ` - : nothing} - - - - ` - } -} - -export function registerLitEditorImageUploadPopover() { - registerLitEditorButton() - registerPopoverPopupElement() - registerPopoverPositionerElement() - registerPopoverRootElement() - registerPopoverTriggerElement() - - if (customElements.get('lit-editor-image-upload-popover')) return - customElements.define( - 'lit-editor-image-upload-popover', - LitImageUploadPopover, - ) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-image-upload-popover': LitImageUploadPopover - } -} diff --git a/lit-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/lit-toolbar/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ff00f20c86..0000000000 --- a/lit-toolbar/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorImageUploadPopover } from './image-upload-popover' diff --git a/lit-toolbar/src/components/editor/ui/toolbar/index.ts b/lit-toolbar/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 6d6df28ea4..0000000000 --- a/lit-toolbar/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { registerLitEditorToolbar } from './toolbar' diff --git a/lit-toolbar/src/components/editor/ui/toolbar/toolbar.ts b/lit-toolbar/src/components/editor/ui/toolbar/toolbar.ts deleted file mode 100644 index ee46ea40a1..0000000000 --- a/lit-toolbar/src/components/editor/ui/toolbar/toolbar.ts +++ /dev/null @@ -1,467 +0,0 @@ -import { ContextConsumer } from '@lit/context' -import { - html, - LitElement, - nothing, - type PropertyDeclaration, - type PropertyValues, -} from 'lit' -import type { BasicExtension } from 'prosekit/basic' -import { defineUpdateHandler, type Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' - -import { registerLitEditorButton } from '../button' -import { editorContext } from '../editor-context' -import { registerLitEditorImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -class LitToolbar extends LitElement { - static override properties = { - uploader: { attribute: false } satisfies PropertyDeclaration< - Uploader - >, - } - - uploader?: Uploader - - private editorConsumer = new ContextConsumer(this, { - context: editorContext, - subscribe: true, - }) - - private removeUpdateExtension?: VoidFunction - - override createRenderRoot() { - return this - } - - override connectedCallback() { - super.connectedCallback() - this.classList.add('contents') - this.attachEditorListener() - } - - override disconnectedCallback() { - this.detachEditorListener() - super.disconnectedCallback() - } - - override updated(changedProperties: PropertyValues) { - super.updated(changedProperties) - this.attachEditorListener() - } - - private attachEditorListener() { - this.detachEditorListener() - - const editor = this.editorConsumer.value - if (!editor) return - - this.removeUpdateExtension = editor.use( - defineUpdateHandler(() => this.requestUpdate()), - ) - } - - private detachEditorListener() { - this.removeUpdateExtension?.() - this.removeUpdateExtension = undefined - } - - override render() { - const editor = this.editorConsumer.value as - | Editor - | undefined - if (!editor) { - return nothing - } - - const items = getToolbarItems(editor) - - return html` -
- ${items.undo - ? html` - - ` - : nothing} - ${items.redo - ? html` - - ` - : nothing} - ${items.bold - ? html` - - ` - : nothing} - ${items.italic - ? html` - - ` - : nothing} - ${items.underline - ? html` - - ` - : nothing} - ${items.strike - ? html` - - ` - : nothing} - ${items.code - ? html` - - ` - : nothing} - ${items.codeBlock - ? html` - - ` - : nothing} - ${items.heading1 - ? html` - - ` - : nothing} - ${items.heading2 - ? html` - - ` - : nothing} - ${items.heading3 - ? html` - - ` - : nothing} - ${items.horizontalRule - ? html` - - ` - : nothing} - ${items.blockquote - ? html` - - ` - : nothing} - ${items.bulletList - ? html` - - ` - : nothing} - ${items.orderedList - ? html` - - ` - : nothing} - ${items.taskList - ? html` - - ` - : nothing} - ${items.toggleList - ? html` - - ` - : nothing} - ${items.indentList - ? html` - - ` - : nothing} - ${items.dedentList - ? html` - - ` - : nothing} - ${this.uploader && items.insertImage - ? html` - - ` - : nothing} -
- ` - } -} - -export function registerLitEditorToolbar() { - registerLitEditorButton() - registerLitEditorImageUploadPopover() - - if (customElements.get('lit-editor-toolbar')) return - customElements.define('lit-editor-toolbar', LitToolbar) -} - -declare global { - interface HTMLElementTagNameMap { - 'lit-editor-toolbar': LitToolbar - } -} diff --git a/lit-toolbar/src/editor.ts b/lit-toolbar/src/editor.ts deleted file mode 100644 index 6eed3b2649..0000000000 --- a/lit-toolbar/src/editor.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { registerLitEditor } from './components/editor/examples/toolbar' -import { LitElement, html } from 'lit' -import { customElement } from 'lit/decorators.js' - -registerLitEditor() - -@customElement('my-editor') -export class MyEditor extends LitElement { - createRenderRoot() { - return this - } - - render() { - return html` - - ` - } -} diff --git a/lit-toolbar/tsconfig.json b/lit-toolbar/tsconfig.json deleted file mode 100644 index f3ad657d5f..0000000000 --- a/lit-toolbar/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "es2023", - "experimentalDecorators": true, - "useDefineForClassFields": false, - "module": "esnext", - "lib": ["ES2023", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/lit-toolbar/vite.config.ts b/lit-toolbar/vite.config.ts deleted file mode 100644 index fb0cdf00b5..0000000000 --- a/lit-toolbar/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [tailwindcss()], -}) diff --git a/next-full/.gitignore b/next-full/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/next-full/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/next-full/README.md b/next-full/README.md deleted file mode 100644 index ee0d54d4fa..0000000000 --- a/next-full/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# next-full - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/next-full) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/next-full) - -Run the example locally with: - -```bash -npx degit prosekit/examples/next-full next-full -cd next-full -npm install -npm run dev -``` diff --git a/next-full/app/app.css b/next-full/app/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/next-full/app/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/next-full/app/layout.tsx b/next-full/app/layout.tsx deleted file mode 100644 index 42ac1c6fe4..0000000000 --- a/next-full/app/layout.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { Metadata } from 'next' -import { Inter } from 'next/font/google' -import './app.css' - -const inter = Inter({ subsets: ['latin'] }) - -export const metadata: Metadata = { - title: 'Create Next App', - description: 'Generated by create next app', -} - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode -}>) { - return ( - - {children} - - ) -} diff --git a/next-full/app/page.tsx b/next-full/app/page.tsx deleted file mode 100644 index e96a9ac6b5..0000000000 --- a/next-full/app/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import Editor from '@/components/editor-dynamic' - -export default function Home() { - return ( -
- -
- ) -} diff --git a/next-full/components/editor-dynamic.tsx b/next-full/components/editor-dynamic.tsx deleted file mode 100644 index beb742d59a..0000000000 --- a/next-full/components/editor-dynamic.tsx +++ /dev/null @@ -1,15 +0,0 @@ -'use client' - -import dynamic from 'next/dynamic' - -const EditorLazy = dynamic( - async () => { - const { ExampleEditor } = await import('./editor/examples/full') - return { default: ExampleEditor } - }, - { ssr: false }, -) - -export default function Editor() { - return -} diff --git a/next-full/components/editor/examples/full/editor.tsx b/next-full/components/editor/examples/full/editor.tsx deleted file mode 100644 index d49fac1be9..0000000000 --- a/next-full/components/editor/examples/full/editor.tsx +++ /dev/null @@ -1,56 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-full' -import { tags } from '../../sample/sample-tag-data' -import { sampleUploader } from '../../sample/sample-uploader' -import { users } from '../../sample/sample-user-data' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' -import { InlineMenu } from '../../ui/inline-menu' -import { SlashMenu } from '../../ui/slash-menu' -import { TableHandle } from '../../ui/table-handle' -import { TagMenu } from '../../ui/tag-menu' -import { Toolbar } from '../../ui/toolbar' -import { UserMenu } from '../../ui/user-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
- - - - - - - -
-
-
- ) -} diff --git a/next-full/components/editor/examples/full/extension.ts b/next-full/components/editor/examples/full/extension.ts deleted file mode 100644 index 5fc2f60685..0000000000 --- a/next-full/components/editor/examples/full/extension.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineImageUploadHandler } from 'prosekit/extensions/image' -import { defineMath } from 'prosekit/extensions/math' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' -import { sampleUploader } from '../../sample/sample-uploader' -import { defineCodeBlockView } from '../../ui/code-block-view' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - defineMention(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - defineCodeBlockShiki(), - defineHorizontalRule(), - defineCodeBlockView(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/next-full/components/editor/examples/full/html.ts b/next-full/components/editor/examples/full/html.ts deleted file mode 100644 index 4945ec9108..0000000000 --- a/next-full/components/editor/examples/full/html.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { createEditor, type NodeJSON } from 'prosekit/core' - -import { sampleContent } from '../../sample/sample-doc-full' - -import { defineExtension } from './extension' - -/** - * Renders a ProseMirror document JSON object to an HTML string. - * - * This is useful for server-side rendering. - * - * @example - * - * ```js - * import { JSDOM } from 'jsdom' - * const dom = new JSDOM('') - * const document = dom.window.document - * const html = renderHTML(document, myContentJSON) - * ``` - */ -export function renderHTML( - document: Document, - content: NodeJSON = sampleContent, -): string { - const extension = defineExtension() - const editor = createEditor({ extension }) - editor.setContent(content) - const html: string = editor.getDocHTML({ document }) - if (html.startsWith('
') && html.endsWith('
')) { - return html.slice(5, -6) // Remove the wrapping
tags - } else { - console.error('Unexpected HTML format: expected a single
wrapper') - return html - } -} diff --git a/next-full/components/editor/examples/full/index.ts b/next-full/components/editor/examples/full/index.ts deleted file mode 100644 index 516b54a1f0..0000000000 --- a/next-full/components/editor/examples/full/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as ExampleEditor } from './editor' -export { renderHTML } from './html' diff --git a/next-full/components/editor/sample/katex.ts b/next-full/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/next-full/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/next-full/components/editor/sample/sample-doc-full.ts b/next-full/components/editor/sample/sample-doc-full.ts deleted file mode 100644 index 13e49b634d..0000000000 --- a/next-full/components/editor/sample/sample-doc-full.ts +++ /dev/null @@ -1,442 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'The editor that thinks like you' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', - }, - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'writing without barriers', - }, - { type: 'text', text: '.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Text that shines.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Make your words ' }, - { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, - { type: 'text', text: ', or ' }, - { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, - { type: 'text', text: '. Add ' }, - { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, - { type: 'text', text: ' that stands out. Create ' }, - { - type: 'text', - marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], - text: 'links', - }, - { type: 'text', text: ' that connect.' }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Select any text to format it. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '@' }, - { type: 'text', text: ' to mention ' }, - { - type: 'mention', - attrs: { id: '39', value: '@someone', kind: 'user' }, - }, - { type: 'text', text: ' or ' }, - { type: 'text', marks: [{ type: 'code' }], text: '#' }, - { type: 'text', text: ' for ' }, - { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, - { type: 'text', text: '. Press ' }, - { type: 'text', marks: [{ type: 'code' }], text: '/' }, - { type: 'text', text: " and discover what's possible." }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Lists that organize.' }], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Bullet points that guide thoughts' }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Nested lists for complex ideas' }], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sub-points flow naturally' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Tasks that focus' }], - }, - { - type: 'list', - attrs: { kind: 'task', order: null, checked: true, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Done feels good' }], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Todo drives action' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Numbered steps' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sequential thinking' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Clear progress' }], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Code that inspires.' }], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Images that captivate.' }], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/season/320x240/107', - }, - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the handle in the bottom right corner to resize.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Tables that structure.' }], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'Feature', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'How to use', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Format text' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Select and choose' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Perfect styling' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Add mentions' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Type @ and name' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Connected ideas' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Insert anything' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Press / for menu' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Endless possibilities' }], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Math that renders.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Inline math like ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' appears within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Quotes that inspire.' }], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: '"This is not just an editor. This is how writing should feel."', - }, - ], - }, - ], - }, - { type: 'horizontalRule' }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Start typing. Everything else just flows.' }, - ], - }, - ], -} diff --git a/next-full/components/editor/sample/sample-tag-data.ts b/next-full/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/next-full/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/next-full/components/editor/sample/sample-uploader.ts b/next-full/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/next-full/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/next-full/components/editor/sample/sample-user-data.ts b/next-full/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/next-full/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/next-full/components/editor/ui/block-handle/block-handle.tsx b/next-full/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 3cc6028d5c..0000000000 --- a/next-full/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' - -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/react/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/next-full/components/editor/ui/block-handle/index.ts b/next-full/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/next-full/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/next-full/components/editor/ui/button/button.tsx b/next-full/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/next-full/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/next-full/components/editor/ui/button/index.ts b/next-full/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/next-full/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/next-full/components/editor/ui/code-block-view/code-block-view.tsx b/next-full/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index f6c0428091..0000000000 --- a/next-full/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { ReactNodeViewProps } from 'prosekit/react' - -export default function CodeBlockView(props: ReactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/next-full/components/editor/ui/code-block-view/index.ts b/next-full/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index b7e6b996bc..0000000000
--- a/next-full/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineReactNodeView,
-  type ReactNodeViewComponent,
-} from 'prosekit/react'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineReactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies ReactNodeViewComponent,
-  })
-}
diff --git a/next-full/components/editor/ui/drop-indicator/drop-indicator.tsx b/next-full/components/editor/ui/drop-indicator/drop-indicator.tsx
deleted file mode 100644
index 87c1746622..0000000000
--- a/next-full/components/editor/ui/drop-indicator/drop-indicator.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-'use client'
-
-import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator'
-
-export default function DropIndicator() {
-  return 
-}
diff --git a/next-full/components/editor/ui/drop-indicator/index.ts b/next-full/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index f8fb7139c4..0000000000
--- a/next-full/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator'
diff --git a/next-full/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/next-full/components/editor/ui/image-upload-popover/image-upload-popover.tsx
deleted file mode 100644
index 808361b6ad..0000000000
--- a/next-full/components/editor/ui/image-upload-popover/image-upload-popover.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-'use client'
-
-import type { Uploader } from 'prosekit/extensions/file'
-import type { ImageExtension } from 'prosekit/extensions/image'
-import { useEditor } from 'prosekit/react'
-import {
-  PopoverPopup,
-  PopoverPositioner,
-  PopoverRoot,
-  PopoverTrigger,
-} from 'prosekit/react/popover'
-import type { OpenChangeEvent } from 'prosekit/web/popover'
-import { useId, useState, type ReactNode } from 'react'
-
-import { Button } from '../button'
-
-export default function ImageUploadPopover(props: {
-  uploader: Uploader
-  tooltip: string
-  disabled: boolean
-  children: ReactNode
-}) {
-  const [open, setOpen] = useState(false)
-  const [url, setUrl] = useState('')
-  const [file, setFile] = useState(null)
-  const ariaId = useId()
-
-  const editor = useEditor()
-
-  const handleFileChange: React.ChangeEventHandler = (
-    event,
-  ) => {
-    const file = event.target.files?.[0]
-
-    if (file) {
-      setFile(file)
-      setUrl('')
-    } else {
-      setFile(null)
-    }
-  }
-
-  const handleUrlChange: React.ChangeEventHandler = (
-    event,
-  ) => {
-    const url = event.target.value
-
-    if (url) {
-      setUrl(url)
-      setFile(null)
-    } else {
-      setUrl('')
-    }
-  }
-
-  const deferResetState = () => {
-    setTimeout(() => {
-      setUrl('')
-      setFile(null)
-    }, 300)
-  }
-
-  const handleSubmit = () => {
-    if (url) {
-      editor.commands.insertImage({ src: url })
-    } else if (file) {
-      editor.commands.uploadImage({ file, uploader: props.uploader })
-    }
-    setOpen(false)
-    deferResetState()
-  }
-
-  const handleOpenChange = (event: OpenChangeEvent) => {
-    if (!event.detail) {
-      deferResetState()
-    }
-    setOpen(event.detail)
-  }
-
-  return (
-    
-      
-        
-      
-
-      
-        
-          {file ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? (
-            
-          ) : null}
-
-          {file ? (
-            
-          ) : null}
-        
-      
-    
-  )
-}
diff --git a/next-full/components/editor/ui/image-upload-popover/index.ts b/next-full/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index 5d49d873ce..0000000000
--- a/next-full/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/next-full/components/editor/ui/image-view/image-view.tsx b/next-full/components/editor/ui/image-view/image-view.tsx
deleted file mode 100644
index 06da475774..0000000000
--- a/next-full/components/editor/ui/image-view/image-view.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-'use client'
-
-import { UploadTask } from 'prosekit/extensions/file'
-import type { ImageAttrs } from 'prosekit/extensions/image'
-import type { ReactNodeViewProps } from 'prosekit/react'
-import { ResizableHandle, ResizableRoot } from 'prosekit/react/resizable'
-import { useEffect, useState, type SyntheticEvent } from 'react'
-
-export default function ImageView(props: ReactNodeViewProps) {
-  const attrs = props.node.attrs as ImageAttrs
-  const url = attrs.src || ''
-  const uploading = url.startsWith('blob:')
-
-  const [aspectRatio, setAspectRatio] = useState()
-  const [error, setError] = useState()
-  const [progress, setProgress] = useState(0)
-
-  useEffect(() => {
-    if (!uploading) return
-
-    const uploadTask = UploadTask.get(url)
-    if (!uploadTask) return
-
-    let canceled = false
-
-    uploadTask.finished.catch((error) => {
-      if (canceled) return
-      setError(String(error))
-    })
-    const unsubscribeProgress = uploadTask.subscribeProgress(
-      ({ loaded, total }) => {
-        if (canceled) return
-        setProgress(total ? loaded / total : 0)
-      },
-    )
-
-    return () => {
-      canceled = true
-      unsubscribeProgress()
-    }
-  }, [url, uploading])
-
-  const handleImageLoad = (event: SyntheticEvent) => {
-    const img = event.target as HTMLImageElement
-    const { naturalWidth, naturalHeight } = img
-    const ratio = naturalWidth / naturalHeight
-    if (ratio && Number.isFinite(ratio)) {
-      setAspectRatio(ratio)
-    }
-    if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) {
-      props.setAttrs({ width: naturalWidth, height: naturalHeight })
-    }
-  }
-
-  return (
-     props.setAttrs(event.detail)}
-      data-selected={props.selected ? '' : undefined}
-      className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid"
-    >
-      {url && !error && (
-        upload preview
-      )}
-      {uploading && !error && (
-        
-
-
{Math.round(progress * 100)}%
-
- )} - {error && ( -
-
-
- Failed to upload image -
-
- )} - -
-
-
- ) -} diff --git a/next-full/components/editor/ui/image-view/index.ts b/next-full/components/editor/ui/image-view/index.ts deleted file mode 100644 index c4a95f9d3f..0000000000 --- a/next-full/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - defineReactNodeView, - type ReactNodeViewComponent, -} from 'prosekit/react' - -import ImageView from './image-view' - -export function defineImageView(): Extension { - return defineReactNodeView({ - name: 'image', - component: ImageView satisfies ReactNodeViewComponent, - }) -} diff --git a/next-full/components/editor/ui/inline-menu/index.ts b/next-full/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/next-full/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/next-full/components/editor/ui/inline-menu/inline-menu.tsx b/next-full/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index af1b2bb2b7..0000000000 --- a/next-full/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/react' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/react/inline-popover' -import { useState } from 'react' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/next-full/components/editor/ui/slash-menu/index.ts b/next-full/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/next-full/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/next-full/components/editor/ui/slash-menu/slash-menu-empty.tsx b/next-full/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index d0dca0934a..0000000000 --- a/next-full/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,11 +0,0 @@ -'use client' - -import { AutocompleteEmpty } from 'prosekit/react/autocomplete' - -export default function SlashMenuEmpty() { - return ( - - No results - - ) -} diff --git a/next-full/components/editor/ui/slash-menu/slash-menu-item.tsx b/next-full/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 349c6e8924..0000000000 --- a/next-full/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client' - -import { AutocompleteItem } from 'prosekit/react/autocomplete' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}) { - return ( - - {props.label} - {props.kbd && ( - - {props.kbd} - - )} - - ) -} diff --git a/next-full/components/editor/ui/slash-menu/slash-menu.tsx b/next-full/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index 3738f51aab..0000000000 --- a/next-full/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,102 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/react' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor.commands.setParagraph()} - /> - - editor.commands.setHeading({ level: 1 })} - /> - - editor.commands.setHeading({ level: 2 })} - /> - - editor.commands.setHeading({ level: 3 })} - /> - - editor.commands.wrapInList({ kind: 'bullet' })} - /> - - editor.commands.wrapInList({ kind: 'ordered' })} - /> - - editor.commands.wrapInList({ kind: 'task' })} - /> - - editor.commands.wrapInList({ kind: 'toggle' })} - /> - - editor.commands.setBlockquote()} - /> - - editor.commands.insertTable({ row: 3, col: 3 })} - /> - - editor.commands.insertHorizontalRule()} - /> - - editor.commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/next-full/components/editor/ui/table-handle/index.ts b/next-full/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/next-full/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/next-full/components/editor/ui/table-handle/table-handle.tsx b/next-full/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index b90b351382..0000000000 --- a/next-full/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,188 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/react' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/react/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/react/table-handle' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props) { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - {state.addTableColumnBefore.canExec && ( - - Insert Left - - )} - {state.addTableColumnAfter.canExec && ( - - Insert Right - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableColumn.canExec && ( - - Delete Column - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
- - - - -
-
- - - {state.addTableRowAbove.canExec && ( - - Insert Above - - )} - {state.addTableRowBelow.canExec && ( - - Insert Below - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableRow.canExec && ( - - Delete Row - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
-
- ) -} diff --git a/next-full/components/editor/ui/tag-menu/index.ts b/next-full/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index d344b33a70..0000000000 --- a/next-full/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu' diff --git a/next-full/components/editor/ui/tag-menu/tag-menu.tsx b/next-full/components/editor/ui/tag-menu/tag-menu.tsx deleted file mode 100644 index 711486fcf7..0000000000 --- a/next-full/components/editor/ui/tag-menu/tag-menu.tsx +++ /dev/null @@ -1,54 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/react' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -const regex = /#[\da-z]*$/i - -export default function TagMenu(props: { - tags: { id: number; label: string }[] -}) { - const editor = useEditor>() - - const handleTagInsert = (id: number, label: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '#' + label, - kind: 'tag', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - - - -
- - No results - - - {props.tags.map((tag) => ( - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - ))} -
-
-
-
- ) -} diff --git a/next-full/components/editor/ui/toolbar/index.ts b/next-full/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/next-full/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/next-full/components/editor/ui/toolbar/toolbar.tsx b/next-full/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/next-full/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/next-full/components/editor/ui/user-menu/index.ts b/next-full/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/next-full/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/next-full/components/editor/ui/user-menu/user-menu.tsx b/next-full/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 46555f6382..0000000000 --- a/next-full/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,64 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/react' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}) { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - {props.users.map((user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - ))} -
-
-
-
- ) -} diff --git a/next-full/next.config.mjs b/next-full/next.config.mjs deleted file mode 100644 index 1d6147825a..0000000000 --- a/next-full/next.config.mjs +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {} - -export default nextConfig diff --git a/next-full/package.json b/next-full/package.json deleted file mode 100644 index a9567cd7f4..0000000000 --- a/next-full/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-next-full", - "version": "0.0.0", - "private": true, - "scripts": { - "build": "next build", - "dev": "next dev", - "lint": "next lint", - "start": "next start" - }, - "dependencies": { - "katex": "^0.16.45", - "next": "^16.2.6", - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/postcss": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "postcss": "^8.5.14", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3" - } -} diff --git a/next-full/postcss.config.mjs b/next-full/postcss.config.mjs deleted file mode 100644 index a869506ee4..0000000000 --- a/next-full/postcss.config.mjs +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('postcss-load-config').Config} */ -const config = { - plugins: { - '@tailwindcss/postcss': {}, - }, -} - -export default config diff --git a/next-full/tsconfig.json b/next-full/tsconfig.json deleted file mode 100644 index 98dc46c300..0000000000 --- a/next-full/tsconfig.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2018", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./*"] - } - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts" - ], - "exclude": ["node_modules"] -} diff --git a/nuxt-full/.gitignore b/nuxt-full/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/nuxt-full/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/nuxt-full/README.md b/nuxt-full/README.md deleted file mode 100644 index 32dc0f77a8..0000000000 --- a/nuxt-full/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# nuxt-full - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/nuxt-full) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/nuxt-full) - -Run the example locally with: - -```bash -npx degit prosekit/examples/nuxt-full nuxt-full -cd nuxt-full -npm install -npm run dev -``` diff --git a/nuxt-full/nuxt.config.ts b/nuxt-full/nuxt.config.ts deleted file mode 100644 index 0443b74087..0000000000 --- a/nuxt-full/nuxt.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -// https://nuxt.com/docs/api/configuration/nuxt-config -export default defineNuxtConfig({ - devtools: { enabled: true }, - css: ['~/app.css'], - srcDir: 'src', - postcss: { - plugins: { - '@tailwindcss/postcss': {}, - autoprefixer: {}, - }, - }, -}) diff --git a/nuxt-full/package.json b/nuxt-full/package.json deleted file mode 100644 index b1c84bd9d0..0000000000 --- a/nuxt-full/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-nuxt-full", - "private": true, - "type": "module", - "scripts": { - "build": "nuxt build", - "dev": "nuxt dev", - "generate": "nuxt generate", - "postinstall": "nuxt prepare", - "preview": "nuxt preview" - }, - "dependencies": { - "katex": "^0.16.45", - "nuxt": "^4.4.5", - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/postcss": "^4.3.0", - "autoprefixer": "^10.5.0", - "postcss": "^8.5.14", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3" - } -} diff --git a/nuxt-full/src/app.css b/nuxt-full/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/nuxt-full/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/nuxt-full/src/app.vue b/nuxt-full/src/app.vue deleted file mode 100644 index 8c4decdebf..0000000000 --- a/nuxt-full/src/app.vue +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/examples/full/editor.vue b/nuxt-full/src/components/editor/examples/full/editor.vue deleted file mode 100644 index a81ba14ef8..0000000000 --- a/nuxt-full/src/components/editor/examples/full/editor.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/examples/full/extension.ts b/nuxt-full/src/components/editor/examples/full/extension.ts deleted file mode 100644 index 5fc2f60685..0000000000 --- a/nuxt-full/src/components/editor/examples/full/extension.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineImageUploadHandler } from 'prosekit/extensions/image' -import { defineMath } from 'prosekit/extensions/math' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' -import { sampleUploader } from '../../sample/sample-uploader' -import { defineCodeBlockView } from '../../ui/code-block-view' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - defineMention(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - defineCodeBlockShiki(), - defineHorizontalRule(), - defineCodeBlockView(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/nuxt-full/src/components/editor/examples/full/index.ts b/nuxt-full/src/components/editor/examples/full/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/nuxt-full/src/components/editor/examples/full/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/nuxt-full/src/components/editor/sample/katex.ts b/nuxt-full/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/nuxt-full/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/nuxt-full/src/components/editor/sample/sample-doc-full.ts b/nuxt-full/src/components/editor/sample/sample-doc-full.ts deleted file mode 100644 index 13e49b634d..0000000000 --- a/nuxt-full/src/components/editor/sample/sample-doc-full.ts +++ /dev/null @@ -1,442 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'The editor that thinks like you' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', - }, - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'writing without barriers', - }, - { type: 'text', text: '.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Text that shines.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Make your words ' }, - { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, - { type: 'text', text: ', or ' }, - { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, - { type: 'text', text: '. Add ' }, - { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, - { type: 'text', text: ' that stands out. Create ' }, - { - type: 'text', - marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], - text: 'links', - }, - { type: 'text', text: ' that connect.' }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Select any text to format it. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '@' }, - { type: 'text', text: ' to mention ' }, - { - type: 'mention', - attrs: { id: '39', value: '@someone', kind: 'user' }, - }, - { type: 'text', text: ' or ' }, - { type: 'text', marks: [{ type: 'code' }], text: '#' }, - { type: 'text', text: ' for ' }, - { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, - { type: 'text', text: '. Press ' }, - { type: 'text', marks: [{ type: 'code' }], text: '/' }, - { type: 'text', text: " and discover what's possible." }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Lists that organize.' }], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Bullet points that guide thoughts' }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Nested lists for complex ideas' }], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sub-points flow naturally' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Tasks that focus' }], - }, - { - type: 'list', - attrs: { kind: 'task', order: null, checked: true, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Done feels good' }], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Todo drives action' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Numbered steps' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sequential thinking' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Clear progress' }], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Code that inspires.' }], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Images that captivate.' }], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/season/320x240/107', - }, - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the handle in the bottom right corner to resize.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Tables that structure.' }], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'Feature', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'How to use', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Format text' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Select and choose' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Perfect styling' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Add mentions' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Type @ and name' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Connected ideas' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Insert anything' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Press / for menu' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Endless possibilities' }], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Math that renders.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Inline math like ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' appears within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Quotes that inspire.' }], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: '"This is not just an editor. This is how writing should feel."', - }, - ], - }, - ], - }, - { type: 'horizontalRule' }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Start typing. Everything else just flows.' }, - ], - }, - ], -} diff --git a/nuxt-full/src/components/editor/sample/sample-tag-data.ts b/nuxt-full/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/nuxt-full/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/nuxt-full/src/components/editor/sample/sample-uploader.ts b/nuxt-full/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/nuxt-full/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/nuxt-full/src/components/editor/sample/sample-user-data.ts b/nuxt-full/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/nuxt-full/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/nuxt-full/src/components/editor/ui/block-handle/block-handle.vue b/nuxt-full/src/components/editor/ui/block-handle/block-handle.vue deleted file mode 100644 index ba06a1416a..0000000000 --- a/nuxt-full/src/components/editor/ui/block-handle/block-handle.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/block-handle/index.ts b/nuxt-full/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 2c33eb5726..0000000000 --- a/nuxt-full/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.vue' diff --git a/nuxt-full/src/components/editor/ui/button/button.vue b/nuxt-full/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/nuxt-full/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/button/index.ts b/nuxt-full/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/nuxt-full/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/nuxt-full/src/components/editor/ui/code-block-view/code-block-view.vue b/nuxt-full/src/components/editor/ui/code-block-view/code-block-view.vue deleted file mode 100644 index e04ea8792e..0000000000 --- a/nuxt-full/src/components/editor/ui/code-block-view/code-block-view.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/code-block-view/index.ts b/nuxt-full/src/components/editor/ui/code-block-view/index.ts deleted file mode 100644 index b7beb100de..0000000000 --- a/nuxt-full/src/components/editor/ui/code-block-view/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' - -import CodeBlockView from './code-block-view.vue' - -export function defineCodeBlockView(): Extension { - return defineVueNodeView({ - name: 'codeBlock', - contentAs: 'code', - component: CodeBlockView as VueNodeViewComponent, - }) -} diff --git a/nuxt-full/src/components/editor/ui/drop-indicator/drop-indicator.vue b/nuxt-full/src/components/editor/ui/drop-indicator/drop-indicator.vue deleted file mode 100644 index cac51a8629..0000000000 --- a/nuxt-full/src/components/editor/ui/drop-indicator/drop-indicator.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/drop-indicator/index.ts b/nuxt-full/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index b455b1217b..0000000000 --- a/nuxt-full/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator.vue' diff --git a/nuxt-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/nuxt-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/nuxt-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/image-upload-popover/index.ts b/nuxt-full/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/nuxt-full/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/nuxt-full/src/components/editor/ui/image-view/image-view.vue b/nuxt-full/src/components/editor/ui/image-view/image-view.vue deleted file mode 100644 index a8beb8acd2..0000000000 --- a/nuxt-full/src/components/editor/ui/image-view/image-view.vue +++ /dev/null @@ -1,97 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/image-view/index.ts b/nuxt-full/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index 960e2c64d6..0000000000 --- a/nuxt-full/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' - -import ImageView from './image-view.vue' - -export function defineImageView(): Extension { - return defineVueNodeView({ - name: 'image', - component: ImageView as VueNodeViewComponent, - }) -} diff --git a/nuxt-full/src/components/editor/ui/inline-menu/index.ts b/nuxt-full/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8c72e460c8..0000000000 --- a/nuxt-full/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.vue' diff --git a/nuxt-full/src/components/editor/ui/inline-menu/inline-menu.vue b/nuxt-full/src/components/editor/ui/inline-menu/inline-menu.vue deleted file mode 100644 index cacb76b189..0000000000 --- a/nuxt-full/src/components/editor/ui/inline-menu/inline-menu.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/slash-menu/index.ts b/nuxt-full/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 32d71d61f5..0000000000 --- a/nuxt-full/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu.vue' diff --git a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue deleted file mode 100644 index 50fc5468fb..0000000000 --- a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-item.vue b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-item.vue deleted file mode 100644 index 2d99363b45..0000000000 --- a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-item.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu.vue b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu.vue deleted file mode 100644 index 87090511e3..0000000000 --- a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu.vue +++ /dev/null @@ -1,106 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/table-handle/index.ts b/nuxt-full/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 0132b96b36..0000000000 --- a/nuxt-full/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle.vue' diff --git a/nuxt-full/src/components/editor/ui/table-handle/table-handle.vue b/nuxt-full/src/components/editor/ui/table-handle/table-handle.vue deleted file mode 100644 index a9921a8f37..0000000000 --- a/nuxt-full/src/components/editor/ui/table-handle/table-handle.vue +++ /dev/null @@ -1,204 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/tag-menu/index.ts b/nuxt-full/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index 6cb07b1d1c..0000000000 --- a/nuxt-full/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu.vue' diff --git a/nuxt-full/src/components/editor/ui/tag-menu/tag-menu.vue b/nuxt-full/src/components/editor/ui/tag-menu/tag-menu.vue deleted file mode 100644 index a8928c53a9..0000000000 --- a/nuxt-full/src/components/editor/ui/tag-menu/tag-menu.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/toolbar/index.ts b/nuxt-full/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/nuxt-full/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/nuxt-full/src/components/editor/ui/toolbar/toolbar.vue b/nuxt-full/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/nuxt-full/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/nuxt-full/src/components/editor/ui/user-menu/index.ts b/nuxt-full/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index 29fde1b0b4..0000000000 --- a/nuxt-full/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu.vue' diff --git a/nuxt-full/src/components/editor/ui/user-menu/user-menu.vue b/nuxt-full/src/components/editor/ui/user-menu/user-menu.vue deleted file mode 100644 index 60b4c3131c..0000000000 --- a/nuxt-full/src/components/editor/ui/user-menu/user-menu.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - diff --git a/nuxt-full/src/editor.vue b/nuxt-full/src/editor.vue deleted file mode 100644 index 560ed9299f..0000000000 --- a/nuxt-full/src/editor.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/nuxt-full/tsconfig.json b/nuxt-full/tsconfig.json deleted file mode 100644 index a746f2a70c..0000000000 --- a/nuxt-full/tsconfig.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - // https://nuxt.com/docs/guide/concepts/typescript - "extends": "./.nuxt/tsconfig.json" -} diff --git a/preact-block-handle/.gitignore b/preact-block-handle/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-block-handle/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-block-handle/README.md b/preact-block-handle/README.md deleted file mode 100644 index 8b756b7b1f..0000000000 --- a/preact-block-handle/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-block-handle - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-block-handle) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-block-handle) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-block-handle preact-block-handle -cd preact-block-handle -npm install -npm run dev -``` diff --git a/preact-block-handle/index.html b/preact-block-handle/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-block-handle/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-block-handle/package.json b/preact-block-handle/package.json deleted file mode 100644 index e4754d7c64..0000000000 --- a/preact-block-handle/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-block-handle", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-block-handle/src/App.tsx b/preact-block-handle/src/App.tsx deleted file mode 100644 index 2cb5b6bb8d..0000000000 --- a/preact-block-handle/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/block-handle' - -export default function App() { - return -} diff --git a/preact-block-handle/src/app.css b/preact-block-handle/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-block-handle/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-block-handle/src/components/editor/examples/block-handle/editor.tsx b/preact-block-handle/src/components/editor/examples/block-handle/editor.tsx deleted file mode 100644 index 377510c773..0000000000 --- a/preact-block-handle/src/components/editor/examples/block-handle/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-block-handle' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/preact-block-handle/src/components/editor/examples/block-handle/extension.ts b/preact-block-handle/src/components/editor/examples/block-handle/extension.ts deleted file mode 100644 index 2c6a5383ad..0000000000 --- a/preact-block-handle/src/components/editor/examples/block-handle/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union([defineBasicExtension(), defineCodeBlockView()]) -} - -export type EditorExtension = ReturnType diff --git a/preact-block-handle/src/components/editor/examples/block-handle/index.ts b/preact-block-handle/src/components/editor/examples/block-handle/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-block-handle/src/components/editor/examples/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/preact-block-handle/src/components/editor/sample/sample-doc-block-handle.ts deleted file mode 100644 index 3c6ccdc203..0000000000 --- a/preact-block-handle/src/components/editor/sample/sample-doc-block-handle.ts +++ /dev/null @@ -1,323 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Drag and Drop Demo', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Getting Started', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This paragraph can be moved above or below other blocks.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Different Block Types', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'You can drag paragraphs, headings, lists, code blocks, and more.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Lists Work Too', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This entire list can be dragged', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Individual list items stay together', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try moving this list around', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Ordered lists also support dragging', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The numbering updates automatically', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag this list to see it in action', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Even code blocks can be moved:', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: 'javascript', - }, - content: [ - { - type: 'text', - text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Nested Content', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This blockquote can be moved as a single unit.', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested blockquotes move together with their parent.', - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Try It Yourself', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Practice by moving this paragraph to the top of the document.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Or drag this one to between the headings above.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The drag handles make it easy to reorganize your content exactly how you want it.', - }, - ], - }, - ], -} diff --git a/preact-block-handle/src/components/editor/ui/block-handle/block-handle.tsx b/preact-block-handle/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 8f5fe62e40..0000000000 --- a/preact-block-handle/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/preact/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/preact-block-handle/src/components/editor/ui/block-handle/index.ts b/preact-block-handle/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/preact-block-handle/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/preact-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx b/preact-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index 59e33d3ded..0000000000 --- a/preact-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import type { JSX } from 'preact' -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { PreactNodeViewProps } from 'prosekit/preact' - -export default function CodeBlockView(props: PreactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language || '' - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - const handleChange = (event: JSX.TargetedEvent) => { - setLanguage(event.currentTarget.value) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/preact-block-handle/src/components/editor/ui/code-block-view/index.ts b/preact-block-handle/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index 247f963d7e..0000000000
--- a/preact-block-handle/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  definePreactNodeView,
-  type PreactNodeViewComponent,
-} from 'prosekit/preact'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return definePreactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies PreactNodeViewComponent,
-  })
-}
diff --git a/preact-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/preact-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
deleted file mode 100644
index 6ace546a12..0000000000
--- a/preact-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { DropIndicator as BaseDropIndicator } from 'prosekit/preact/drop-indicator'
-
-export default function DropIndicator() {
-  return 
-}
diff --git a/preact-block-handle/src/components/editor/ui/drop-indicator/index.ts b/preact-block-handle/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index f8fb7139c4..0000000000
--- a/preact-block-handle/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator'
diff --git a/preact-block-handle/src/main.tsx b/preact-block-handle/src/main.tsx
deleted file mode 100644
index 9452b5673a..0000000000
--- a/preact-block-handle/src/main.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import './app.css'
-import { render } from 'preact'
-import App from './App.tsx'
-
-render(, document.getElementById('app')!)
diff --git a/preact-block-handle/tsconfig.app.json b/preact-block-handle/tsconfig.app.json
deleted file mode 100644
index 3fe3ab979d..0000000000
--- a/preact-block-handle/tsconfig.app.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
-    "target": "ES2022",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "lib": ["ES2022", "DOM", "DOM.Iterable"],
-    "types": ["vite/client"],
-    "skipLibCheck": true,
-    "paths": {
-      "react": ["./node_modules/preact/compat/"],
-      "react-dom": ["./node_modules/preact/compat/"]
-    },
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-    "jsx": "react-jsx",
-    "jsxImportSource": "preact",
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["src"]
-}
diff --git a/preact-block-handle/tsconfig.json b/preact-block-handle/tsconfig.json
deleted file mode 100644
index 1ffef600d9..0000000000
--- a/preact-block-handle/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "files": [],
-  "references": [
-    { "path": "./tsconfig.app.json" },
-    { "path": "./tsconfig.node.json" }
-  ]
-}
diff --git a/preact-block-handle/tsconfig.node.json b/preact-block-handle/tsconfig.node.json
deleted file mode 100644
index 8a67f62f4c..0000000000
--- a/preact-block-handle/tsconfig.node.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
-    "target": "ES2023",
-    "lib": ["ES2023"],
-    "module": "ESNext",
-    "types": ["node"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/preact-block-handle/vite.config.ts b/preact-block-handle/vite.config.ts
deleted file mode 100644
index 5e0b3c9e1a..0000000000
--- a/preact-block-handle/vite.config.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { defineConfig } from 'vite'
-import preact from '@preact/preset-vite'
-import tailwindcss from '@tailwindcss/vite'
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  plugins: [preact(), tailwindcss()],
-})
diff --git a/preact-blockquote/.gitignore b/preact-blockquote/.gitignore
deleted file mode 100644
index 5d6225c6df..0000000000
--- a/preact-blockquote/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-dist
-.next
-.svelte-kit
diff --git a/preact-blockquote/README.md b/preact-blockquote/README.md
deleted file mode 100644
index b6f9eb4248..0000000000
--- a/preact-blockquote/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# preact-blockquote
-
-A [ProseKit](https://prosekit.dev) example.
-
-[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-blockquote)
-[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-blockquote)
-
-Run the example locally with:
-
-```bash
-npx degit prosekit/examples/preact-blockquote preact-blockquote
-cd preact-blockquote
-npm install
-npm run dev
-```
diff --git a/preact-blockquote/index.html b/preact-blockquote/index.html
deleted file mode 100644
index b4f79f2233..0000000000
--- a/preact-blockquote/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-  
-    
-    
-    ProseKit + Preact
-  
-  
-    
- - - diff --git a/preact-blockquote/package.json b/preact-blockquote/package.json deleted file mode 100644 index 6d369bb665..0000000000 --- a/preact-blockquote/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-blockquote", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-blockquote/src/App.tsx b/preact-blockquote/src/App.tsx deleted file mode 100644 index 3327cfcf2d..0000000000 --- a/preact-blockquote/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/blockquote' - -export default function App() { - return -} diff --git a/preact-blockquote/src/app.css b/preact-blockquote/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-blockquote/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-blockquote/src/components/editor/examples/blockquote/editor.tsx b/preact-blockquote/src/components/editor/examples/blockquote/editor.tsx deleted file mode 100644 index 47be0af302..0000000000 --- a/preact-blockquote/src/components/editor/examples/blockquote/editor.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - return createEditor({ extension: defineExtension() }) - }, []) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-blockquote/src/components/editor/examples/blockquote/extension.ts b/preact-blockquote/src/components/editor/examples/blockquote/extension.ts deleted file mode 100644 index 5292b59e35..0000000000 --- a/preact-blockquote/src/components/editor/examples/blockquote/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBlockquote(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-blockquote/src/components/editor/examples/blockquote/index.ts b/preact-blockquote/src/components/editor/examples/blockquote/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-blockquote/src/components/editor/examples/blockquote/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-blockquote/src/components/editor/ui/button/button.tsx b/preact-blockquote/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-blockquote/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-blockquote/src/components/editor/ui/button/index.ts b/preact-blockquote/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-blockquote/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/preact-blockquote/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-blockquote/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-blockquote/src/components/editor/ui/toolbar/index.ts b/preact-blockquote/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-blockquote/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-blockquote/src/components/editor/ui/toolbar/toolbar.tsx b/preact-blockquote/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-blockquote/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-blockquote/src/main.tsx b/preact-blockquote/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-blockquote/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-blockquote/tsconfig.app.json b/preact-blockquote/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-blockquote/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-blockquote/tsconfig.json b/preact-blockquote/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-blockquote/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-blockquote/tsconfig.node.json b/preact-blockquote/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-blockquote/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-blockquote/vite.config.ts b/preact-blockquote/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-blockquote/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-bold/.gitignore b/preact-bold/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-bold/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-bold/README.md b/preact-bold/README.md deleted file mode 100644 index 923dac0c8e..0000000000 --- a/preact-bold/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-bold - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-bold) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-bold) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-bold preact-bold -cd preact-bold -npm install -npm run dev -``` diff --git a/preact-bold/index.html b/preact-bold/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-bold/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-bold/package.json b/preact-bold/package.json deleted file mode 100644 index 7588aa22c4..0000000000 --- a/preact-bold/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-bold", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-bold/src/App.tsx b/preact-bold/src/App.tsx deleted file mode 100644 index 274955047d..0000000000 --- a/preact-bold/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/bold' - -export default function App() { - return -} diff --git a/preact-bold/src/app.css b/preact-bold/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-bold/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-bold/src/components/editor/examples/bold/editor.tsx b/preact-bold/src/components/editor/examples/bold/editor.tsx deleted file mode 100644 index 6e699413f5..0000000000 --- a/preact-bold/src/components/editor/examples/bold/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-bold' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-bold/src/components/editor/examples/bold/extension.ts b/preact-bold/src/components/editor/examples/bold/extension.ts deleted file mode 100644 index eaa4fba721..0000000000 --- a/preact-bold/src/components/editor/examples/bold/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBold } from 'prosekit/extensions/bold' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBold(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-bold/src/components/editor/examples/bold/index.ts b/preact-bold/src/components/editor/examples/bold/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-bold/src/components/editor/examples/bold/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-bold/src/components/editor/sample/sample-doc-bold.ts b/preact-bold/src/components/editor/sample/sample-doc-bold.ts deleted file mode 100644 index 09ed08daad..0000000000 --- a/preact-bold/src/components/editor/sample/sample-doc-bold.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/preact-bold/src/components/editor/ui/button/button.tsx b/preact-bold/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-bold/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-bold/src/components/editor/ui/button/index.ts b/preact-bold/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-bold/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-bold/src/components/editor/ui/image-upload-popover/index.ts b/preact-bold/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-bold/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-bold/src/components/editor/ui/toolbar/index.ts b/preact-bold/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-bold/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-bold/src/components/editor/ui/toolbar/toolbar.tsx b/preact-bold/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-bold/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-bold/src/main.tsx b/preact-bold/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-bold/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-bold/tsconfig.app.json b/preact-bold/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-bold/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-bold/tsconfig.json b/preact-bold/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-bold/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-bold/tsconfig.node.json b/preact-bold/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-bold/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-bold/vite.config.ts b/preact-bold/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-bold/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-change-tracking/.gitignore b/preact-change-tracking/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-change-tracking/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-change-tracking/README.md b/preact-change-tracking/README.md deleted file mode 100644 index 2033d9f90d..0000000000 --- a/preact-change-tracking/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-change-tracking - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-change-tracking) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-change-tracking) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-change-tracking preact-change-tracking -cd preact-change-tracking -npm install -npm run dev -``` diff --git a/preact-change-tracking/index.html b/preact-change-tracking/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-change-tracking/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-change-tracking/package.json b/preact-change-tracking/package.json deleted file mode 100644 index ae2e5ef052..0000000000 --- a/preact-change-tracking/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-change-tracking", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-change-tracking/src/App.tsx b/preact-change-tracking/src/App.tsx deleted file mode 100644 index 88160e69c9..0000000000 --- a/preact-change-tracking/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/change-tracking' - -export default function App() { - return -} diff --git a/preact-change-tracking/src/app.css b/preact-change-tracking/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-change-tracking/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx b/preact-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx deleted file mode 100644 index 16afd59ecd..0000000000 --- a/preact-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { useMemo } from 'preact/hooks' -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, union } from 'prosekit/core' -import { defineCommitViewer, type Commit } from 'prosekit/extensions/commit' -import { defineReadonly } from 'prosekit/extensions/readonly' -import { ProseKit } from 'prosekit/preact' - -export default function EditorDiff(props: { commit: Commit }) { - const editor = useMemo(() => { - const extension = union( - defineBasicExtension(), - defineReadonly(), - defineCommitViewer(props.commit), - ) - return createEditor({ extension }) - }, [props.commit]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx b/preact-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx deleted file mode 100644 index cfe4253b0b..0000000000 --- a/preact-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, union, type NodeJSON } from 'prosekit/core' -import { - defineCommitRecorder, - type CommitRecorder, -} from 'prosekit/extensions/commit' -import { ProseKit } from 'prosekit/preact' - -export default function EditorMain(props: { - commitRecorder: CommitRecorder - initialContent?: NodeJSON -}) { - const editor = useMemo(() => { - const extension = union( - defineBasicExtension(), - defineCommitRecorder(props.commitRecorder), - ) - return createEditor({ extension, defaultContent: props.initialContent }) - }, [props.commitRecorder, props.initialContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-change-tracking/src/components/editor/examples/change-tracking/editor.tsx b/preact-change-tracking/src/components/editor/examples/change-tracking/editor.tsx deleted file mode 100644 index cdb9a02d22..0000000000 --- a/preact-change-tracking/src/components/editor/examples/change-tracking/editor.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useCallback, useMemo, useState } from 'preact/hooks' -import type { NodeJSON } from 'prosekit/core' -import { CommitRecorder, type Commit } from 'prosekit/extensions/commit' - -import EditorDiff from './editor-diff' -import EditorMain from './editor-main' - -export default function Editor() { - const [commits, setCommits] = useState< - { id: string; date: Date; commit: Commit }[] - >([]) - const [key, setKey] = useState(0) - const [initialContent, setInitialContent] = useState() - const commitRecorder = useMemo(() => new CommitRecorder(), []) - - const handleCommit = useCallback(() => { - const commit = commitRecorder.commit() - if (!commit) return - const id = Math.random().toString(36).slice(2, 9) - setCommits((existing) => [{ id, date: new Date(), commit }, ...existing]) - }, [commitRecorder]) - - const handleRestore = useCallback( - (id: string) => { - const index = commits.findIndex((commit) => commit.id === id) - const commit = commits[index] - if (index === -1 || !commit) return - const doc = commit.commit.doc - setInitialContent(doc) - setCommits((commits) => commits.slice(index)) - setKey((key) => key + 1) - }, - [commits], - ) - - return ( -
-
-
- -
- -
-
- {commits.map((commit) => ( -
-
- -
-
- - {commit.date.toLocaleTimeString()} - - -
-
- ))} -
-
- ) -} diff --git a/preact-change-tracking/src/components/editor/examples/change-tracking/index.ts b/preact-change-tracking/src/components/editor/examples/change-tracking/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-change-tracking/src/components/editor/examples/change-tracking/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-change-tracking/src/main.tsx b/preact-change-tracking/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-change-tracking/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-change-tracking/tsconfig.app.json b/preact-change-tracking/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-change-tracking/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-change-tracking/tsconfig.json b/preact-change-tracking/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-change-tracking/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-change-tracking/tsconfig.node.json b/preact-change-tracking/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-change-tracking/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-change-tracking/vite.config.ts b/preact-change-tracking/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-change-tracking/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-code-block-themes/.gitignore b/preact-code-block-themes/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-code-block-themes/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-code-block-themes/README.md b/preact-code-block-themes/README.md deleted file mode 100644 index 5c156daad1..0000000000 --- a/preact-code-block-themes/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-code-block-themes - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-code-block-themes) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-code-block-themes) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-code-block-themes preact-code-block-themes -cd preact-code-block-themes -npm install -npm run dev -``` diff --git a/preact-code-block-themes/index.html b/preact-code-block-themes/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-code-block-themes/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-code-block-themes/package.json b/preact-code-block-themes/package.json deleted file mode 100644 index f85fb96f98..0000000000 --- a/preact-code-block-themes/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-code-block-themes", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-code-block-themes/src/App.tsx b/preact-code-block-themes/src/App.tsx deleted file mode 100644 index 9b93464b4e..0000000000 --- a/preact-code-block-themes/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code-block-themes' - -export default function App() { - return -} diff --git a/preact-code-block-themes/src/app.css b/preact-code-block-themes/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-code-block-themes/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx b/preact-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx deleted file mode 100644 index deaadc1187..0000000000 --- a/preact-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-code-block' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/preact-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts deleted file mode 100644 index b5686b8c04..0000000000 --- a/preact-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union(defineBasicExtension(), defineCodeBlockView()) -} - -export type EditorExtension = ReturnType diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/preact-code-block-themes/src/components/editor/examples/code-block-themes/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-code-block-themes/src/components/editor/examples/code-block-themes/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx b/preact-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx deleted file mode 100644 index c1f2729eea..0000000000 --- a/preact-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import type { JSX } from 'preact' -import { useMemo, useState } from 'preact/hooks' -import { - defineCodeBlockShiki, - shikiBundledThemesInfo, - type ShikiBundledTheme, -} from 'prosekit/extensions/code-block' -import { useExtension } from 'prosekit/preact' - -export function ThemeSelector() { - const [theme, setTheme] = useState('github-dark') - const extension = useMemo(() => { - return defineCodeBlockShiki({ themes: [theme as ShikiBundledTheme] }) - }, [theme]) - useExtension(extension) - - const handleChange = (event: JSX.TargetedEvent) => { - setTheme(event.currentTarget.value) - } - - return ( - <> - - - - ) -} diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx b/preact-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx deleted file mode 100644 index 66ebec1e56..0000000000 --- a/preact-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { ThemeSelector } from './theme-selector' - -export default function Toolbar() { - return ( -
- -
- ) -} diff --git a/preact-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/preact-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/preact-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/preact-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx b/preact-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index 59e33d3ded..0000000000 --- a/preact-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import type { JSX } from 'preact' -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { PreactNodeViewProps } from 'prosekit/preact' - -export default function CodeBlockView(props: PreactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language || '' - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - const handleChange = (event: JSX.TargetedEvent) => { - setLanguage(event.currentTarget.value) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/preact-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/preact-code-block-themes/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index 247f963d7e..0000000000
--- a/preact-code-block-themes/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  definePreactNodeView,
-  type PreactNodeViewComponent,
-} from 'prosekit/preact'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return definePreactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies PreactNodeViewComponent,
-  })
-}
diff --git a/preact-code-block-themes/src/main.tsx b/preact-code-block-themes/src/main.tsx
deleted file mode 100644
index 9452b5673a..0000000000
--- a/preact-code-block-themes/src/main.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import './app.css'
-import { render } from 'preact'
-import App from './App.tsx'
-
-render(, document.getElementById('app')!)
diff --git a/preact-code-block-themes/tsconfig.app.json b/preact-code-block-themes/tsconfig.app.json
deleted file mode 100644
index 3fe3ab979d..0000000000
--- a/preact-code-block-themes/tsconfig.app.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
-    "target": "ES2022",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "lib": ["ES2022", "DOM", "DOM.Iterable"],
-    "types": ["vite/client"],
-    "skipLibCheck": true,
-    "paths": {
-      "react": ["./node_modules/preact/compat/"],
-      "react-dom": ["./node_modules/preact/compat/"]
-    },
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-    "jsx": "react-jsx",
-    "jsxImportSource": "preact",
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["src"]
-}
diff --git a/preact-code-block-themes/tsconfig.json b/preact-code-block-themes/tsconfig.json
deleted file mode 100644
index 1ffef600d9..0000000000
--- a/preact-code-block-themes/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "files": [],
-  "references": [
-    { "path": "./tsconfig.app.json" },
-    { "path": "./tsconfig.node.json" }
-  ]
-}
diff --git a/preact-code-block-themes/tsconfig.node.json b/preact-code-block-themes/tsconfig.node.json
deleted file mode 100644
index 8a67f62f4c..0000000000
--- a/preact-code-block-themes/tsconfig.node.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
-    "target": "ES2023",
-    "lib": ["ES2023"],
-    "module": "ESNext",
-    "types": ["node"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/preact-code-block-themes/vite.config.ts b/preact-code-block-themes/vite.config.ts
deleted file mode 100644
index 5e0b3c9e1a..0000000000
--- a/preact-code-block-themes/vite.config.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { defineConfig } from 'vite'
-import preact from '@preact/preset-vite'
-import tailwindcss from '@tailwindcss/vite'
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  plugins: [preact(), tailwindcss()],
-})
diff --git a/preact-code-block/.gitignore b/preact-code-block/.gitignore
deleted file mode 100644
index 5d6225c6df..0000000000
--- a/preact-code-block/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-dist
-.next
-.svelte-kit
diff --git a/preact-code-block/README.md b/preact-code-block/README.md
deleted file mode 100644
index 2b711d1606..0000000000
--- a/preact-code-block/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# preact-code-block
-
-A [ProseKit](https://prosekit.dev) example.
-
-[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-code-block)
-[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-code-block)
-
-Run the example locally with:
-
-```bash
-npx degit prosekit/examples/preact-code-block preact-code-block
-cd preact-code-block
-npm install
-npm run dev
-```
diff --git a/preact-code-block/index.html b/preact-code-block/index.html
deleted file mode 100644
index b4f79f2233..0000000000
--- a/preact-code-block/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-  
-    
-    
-    ProseKit + Preact
-  
-  
-    
- - - diff --git a/preact-code-block/package.json b/preact-code-block/package.json deleted file mode 100644 index 608adce773..0000000000 --- a/preact-code-block/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-code-block", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-code-block/src/App.tsx b/preact-code-block/src/App.tsx deleted file mode 100644 index 961ce70aad..0000000000 --- a/preact-code-block/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code-block' - -export default function App() { - return -} diff --git a/preact-code-block/src/app.css b/preact-code-block/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-code-block/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-code-block/src/components/editor/examples/code-block/editor.tsx b/preact-code-block/src/components/editor/examples/code-block/editor.tsx deleted file mode 100644 index 10a3458f9d..0000000000 --- a/preact-code-block/src/components/editor/examples/code-block/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-code-block' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-code-block/src/components/editor/examples/code-block/extension.ts b/preact-code-block/src/components/editor/examples/code-block/extension.ts deleted file mode 100644 index 099cacf03b..0000000000 --- a/preact-code-block/src/components/editor/examples/code-block/extension.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { - defineCodeBlock, - defineCodeBlockShiki, -} from 'prosekit/extensions/code-block' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCodeBlock(), - defineCodeBlockShiki(), - defineCodeBlockView(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-code-block/src/components/editor/examples/code-block/index.ts b/preact-code-block/src/components/editor/examples/code-block/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-code-block/src/components/editor/examples/code-block/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-code-block/src/components/editor/sample/sample-doc-code-block.ts b/preact-code-block/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/preact-code-block/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/preact-code-block/src/components/editor/ui/button/button.tsx b/preact-code-block/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-code-block/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-code-block/src/components/editor/ui/button/index.ts b/preact-code-block/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-code-block/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx b/preact-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index 59e33d3ded..0000000000 --- a/preact-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import type { JSX } from 'preact' -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { PreactNodeViewProps } from 'prosekit/preact' - -export default function CodeBlockView(props: PreactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language || '' - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - const handleChange = (event: JSX.TargetedEvent) => { - setLanguage(event.currentTarget.value) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/preact-code-block/src/components/editor/ui/code-block-view/index.ts b/preact-code-block/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index 247f963d7e..0000000000
--- a/preact-code-block/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  definePreactNodeView,
-  type PreactNodeViewComponent,
-} from 'prosekit/preact'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return definePreactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies PreactNodeViewComponent,
-  })
-}
diff --git a/preact-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
deleted file mode 100644
index 764667a8c0..0000000000
--- a/preact-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-import type { ComponentChild, JSX } from 'preact'
-import { useId, useState } from 'preact/hooks'
-import type { Uploader } from 'prosekit/extensions/file'
-import type { ImageExtension } from 'prosekit/extensions/image'
-import { useEditor } from 'prosekit/preact'
-import {
-  PopoverPopup,
-  PopoverPositioner,
-  PopoverRoot,
-  PopoverTrigger,
-} from 'prosekit/preact/popover'
-import type { OpenChangeEvent } from 'prosekit/web/popover'
-
-import { Button } from '../button'
-
-export default function ImageUploadPopover(props: {
-  uploader: Uploader
-  tooltip: string
-  disabled: boolean
-  children: ComponentChild
-}) {
-  const [open, setOpen] = useState(false)
-  const [url, setUrl] = useState('')
-  const [file, setFile] = useState(null)
-  const ariaId = useId()
-
-  const editor = useEditor()
-
-  const handleFileChange = (
-    event: JSX.TargetedEvent,
-  ) => {
-    const file = event.currentTarget.files?.[0]
-
-    if (file) {
-      setFile(file)
-      setUrl('')
-    } else {
-      setFile(null)
-    }
-  }
-
-  const handleUrlChange = (
-    event: JSX.TargetedEvent,
-  ) => {
-    const url = event.currentTarget.value
-
-    if (url) {
-      setUrl(url)
-      setFile(null)
-    } else {
-      setUrl('')
-    }
-  }
-
-  const deferResetState = () => {
-    setTimeout(() => {
-      setUrl('')
-      setFile(null)
-    }, 300)
-  }
-
-  const handleSubmit = () => {
-    if (url) {
-      editor.commands.insertImage({ src: url })
-    } else if (file) {
-      editor.commands.uploadImage({ file, uploader: props.uploader })
-    }
-    setOpen(false)
-    deferResetState()
-  }
-
-  const handleOpenChange = (event: OpenChangeEvent) => {
-    if (!event.detail) {
-      deferResetState()
-    }
-    setOpen(event.detail)
-  }
-
-  return (
-    
-      
-        
-      
-
-      
-        
-          {file ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? (
-            
-          ) : null}
-
-          {file ? (
-            
-          ) : null}
-        
-      
-    
-  )
-}
diff --git a/preact-code-block/src/components/editor/ui/image-upload-popover/index.ts b/preact-code-block/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index 5d49d873ce..0000000000
--- a/preact-code-block/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/preact-code-block/src/components/editor/ui/toolbar/index.ts b/preact-code-block/src/components/editor/ui/toolbar/index.ts
deleted file mode 100644
index fdf6741e6a..0000000000
--- a/preact-code-block/src/components/editor/ui/toolbar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as Toolbar } from './toolbar'
diff --git a/preact-code-block/src/components/editor/ui/toolbar/toolbar.tsx b/preact-code-block/src/components/editor/ui/toolbar/toolbar.tsx
deleted file mode 100644
index 746a58435a..0000000000
--- a/preact-code-block/src/components/editor/ui/toolbar/toolbar.tsx
+++ /dev/null
@@ -1,363 +0,0 @@
-import type { BasicExtension } from 'prosekit/basic'
-import type { Editor } from 'prosekit/core'
-import type { Uploader } from 'prosekit/extensions/file'
-import { useEditorDerivedValue } from 'prosekit/preact'
-
-import { Button } from '../button'
-import { ImageUploadPopover } from '../image-upload-popover'
-
-function getToolbarItems(editor: Editor) {
-  return {
-    undo: editor.commands.undo
-      ? {
-          isActive: false,
-          canExec: editor.commands.undo.canExec(),
-          command: () => editor.commands.undo(),
-        }
-      : undefined,
-    redo: editor.commands.redo
-      ? {
-          isActive: false,
-          canExec: editor.commands.redo.canExec(),
-          command: () => editor.commands.redo(),
-        }
-      : undefined,
-    bold: editor.commands.toggleBold
-      ? {
-          isActive: editor.marks.bold.isActive(),
-          canExec: editor.commands.toggleBold.canExec(),
-          command: () => editor.commands.toggleBold(),
-        }
-      : undefined,
-    italic: editor.commands.toggleItalic
-      ? {
-          isActive: editor.marks.italic.isActive(),
-          canExec: editor.commands.toggleItalic.canExec(),
-          command: () => editor.commands.toggleItalic(),
-        }
-      : undefined,
-    underline: editor.commands.toggleUnderline
-      ? {
-          isActive: editor.marks.underline.isActive(),
-          canExec: editor.commands.toggleUnderline.canExec(),
-          command: () => editor.commands.toggleUnderline(),
-        }
-      : undefined,
-    strike: editor.commands.toggleStrike
-      ? {
-          isActive: editor.marks.strike.isActive(),
-          canExec: editor.commands.toggleStrike.canExec(),
-          command: () => editor.commands.toggleStrike(),
-        }
-      : undefined,
-    code: editor.commands.toggleCode
-      ? {
-          isActive: editor.marks.code.isActive(),
-          canExec: editor.commands.toggleCode.canExec(),
-          command: () => editor.commands.toggleCode(),
-        }
-      : undefined,
-    codeBlock: editor.commands.insertCodeBlock
-      ? {
-          isActive: editor.nodes.codeBlock.isActive(),
-          canExec: editor.commands.insertCodeBlock.canExec({
-            language: 'javascript',
-          }),
-          command: () =>
-            editor.commands.insertCodeBlock({ language: 'javascript' }),
-        }
-      : undefined,
-    heading1: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 1 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 1 }),
-          command: () => editor.commands.toggleHeading({ level: 1 }),
-        }
-      : undefined,
-    heading2: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 2 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 2 }),
-          command: () => editor.commands.toggleHeading({ level: 2 }),
-        }
-      : undefined,
-    heading3: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 3 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 3 }),
-          command: () => editor.commands.toggleHeading({ level: 3 }),
-        }
-      : undefined,
-    horizontalRule: editor.commands.insertHorizontalRule
-      ? {
-          isActive: editor.nodes.horizontalRule.isActive(),
-          canExec: editor.commands.insertHorizontalRule.canExec(),
-          command: () => editor.commands.insertHorizontalRule(),
-        }
-      : undefined,
-    blockquote: editor.commands.toggleBlockquote
-      ? {
-          isActive: editor.nodes.blockquote.isActive(),
-          canExec: editor.commands.toggleBlockquote.canExec(),
-          command: () => editor.commands.toggleBlockquote(),
-        }
-      : undefined,
-    bulletList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'bullet' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }),
-          command: () => editor.commands.toggleList({ kind: 'bullet' }),
-        }
-      : undefined,
-    orderedList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'ordered' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }),
-          command: () => editor.commands.toggleList({ kind: 'ordered' }),
-        }
-      : undefined,
-    taskList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'task' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'task' }),
-          command: () => editor.commands.toggleList({ kind: 'task' }),
-        }
-      : undefined,
-    toggleList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'toggle' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }),
-          command: () => editor.commands.toggleList({ kind: 'toggle' }),
-        }
-      : undefined,
-    indentList: editor.commands.indentList
-      ? {
-          isActive: false,
-          canExec: editor.commands.indentList.canExec(),
-          command: () => editor.commands.indentList(),
-        }
-      : undefined,
-    dedentList: editor.commands.dedentList
-      ? {
-          isActive: false,
-          canExec: editor.commands.dedentList.canExec(),
-          command: () => editor.commands.dedentList(),
-        }
-      : undefined,
-    insertImage: editor.commands.insertImage
-      ? {
-          isActive: false,
-          canExec: editor.commands.insertImage.canExec(),
-        }
-      : undefined,
-  }
-}
-
-export default function Toolbar(props: { uploader?: Uploader }) {
-  const items = useEditorDerivedValue(getToolbarItems)
-
-  return (
-    
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-code-block/src/main.tsx b/preact-code-block/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-code-block/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-code-block/tsconfig.app.json b/preact-code-block/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-code-block/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-code-block/tsconfig.json b/preact-code-block/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-code-block/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-code-block/tsconfig.node.json b/preact-code-block/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-code-block/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-code-block/vite.config.ts b/preact-code-block/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-code-block/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-code/.gitignore b/preact-code/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-code/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-code/README.md b/preact-code/README.md deleted file mode 100644 index 079055fbad..0000000000 --- a/preact-code/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-code - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-code) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-code) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-code preact-code -cd preact-code -npm install -npm run dev -``` diff --git a/preact-code/index.html b/preact-code/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-code/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-code/package.json b/preact-code/package.json deleted file mode 100644 index 4ce228ea74..0000000000 --- a/preact-code/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-code", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-code/src/App.tsx b/preact-code/src/App.tsx deleted file mode 100644 index f2f5d9a360..0000000000 --- a/preact-code/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code' - -export default function App() { - return -} diff --git a/preact-code/src/app.css b/preact-code/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-code/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-code/src/components/editor/examples/code/editor.tsx b/preact-code/src/components/editor/examples/code/editor.tsx deleted file mode 100644 index a3b39cd30f..0000000000 --- a/preact-code/src/components/editor/examples/code/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-code' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-code/src/components/editor/examples/code/extension.ts b/preact-code/src/components/editor/examples/code/extension.ts deleted file mode 100644 index e9e273216e..0000000000 --- a/preact-code/src/components/editor/examples/code/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCode(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-code/src/components/editor/examples/code/index.ts b/preact-code/src/components/editor/examples/code/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-code/src/components/editor/examples/code/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-code/src/components/editor/sample/sample-doc-code.ts b/preact-code/src/components/editor/sample/sample-doc-code.ts deleted file mode 100644 index 2fdbcee1f3..0000000000 --- a/preact-code/src/components/editor/sample/sample-doc-code.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'This is code', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/preact-code/src/components/editor/ui/button/button.tsx b/preact-code/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-code/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-code/src/components/editor/ui/button/index.ts b/preact-code/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-code/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-code/src/components/editor/ui/image-upload-popover/index.ts b/preact-code/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-code/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-code/src/components/editor/ui/toolbar/index.ts b/preact-code/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-code/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-code/src/components/editor/ui/toolbar/toolbar.tsx b/preact-code/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-code/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-code/src/main.tsx b/preact-code/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-code/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-code/tsconfig.app.json b/preact-code/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-code/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-code/tsconfig.json b/preact-code/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-code/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-code/tsconfig.node.json b/preact-code/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-code/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-code/vite.config.ts b/preact-code/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-code/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-drop-cursor/.gitignore b/preact-drop-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-drop-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-drop-cursor/README.md b/preact-drop-cursor/README.md deleted file mode 100644 index a0d9f533a0..0000000000 --- a/preact-drop-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-drop-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-drop-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-drop-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-drop-cursor preact-drop-cursor -cd preact-drop-cursor -npm install -npm run dev -``` diff --git a/preact-drop-cursor/index.html b/preact-drop-cursor/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-drop-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-drop-cursor/package.json b/preact-drop-cursor/package.json deleted file mode 100644 index bbece0ba5e..0000000000 --- a/preact-drop-cursor/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-drop-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-drop-cursor/src/App.tsx b/preact-drop-cursor/src/App.tsx deleted file mode 100644 index f66459b286..0000000000 --- a/preact-drop-cursor/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/drop-cursor' - -export default function App() { - return -} diff --git a/preact-drop-cursor/src/app.css b/preact-drop-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-drop-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx b/preact-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx deleted file mode 100644 index 8da7c938f1..0000000000 --- a/preact-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-drop-cursor' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/preact-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts deleted file mode 100644 index fd79a2c96c..0000000000 --- a/preact-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineImage(), - defineDropCursor({ - color: false, - width: 4, - class: 'transition-all bg-blue-500', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/preact-drop-cursor/src/components/editor/examples/drop-cursor/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-drop-cursor/src/components/editor/examples/drop-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/preact-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts deleted file mode 100644 index 22c6b93465..0000000000 --- a/preact-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the images below to see the custom drop cursor.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/320x240/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/green/320x240/40', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blue/320x240/187', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/red/320x240/188', - }, - }, - ], -} diff --git a/preact-drop-cursor/src/main.tsx b/preact-drop-cursor/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-drop-cursor/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-drop-cursor/tsconfig.app.json b/preact-drop-cursor/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-drop-cursor/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-drop-cursor/tsconfig.json b/preact-drop-cursor/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-drop-cursor/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-drop-cursor/tsconfig.node.json b/preact-drop-cursor/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-drop-cursor/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-drop-cursor/vite.config.ts b/preact-drop-cursor/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-drop-cursor/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-emoji-rules/.gitignore b/preact-emoji-rules/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-emoji-rules/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-emoji-rules/README.md b/preact-emoji-rules/README.md deleted file mode 100644 index 72ba488c3d..0000000000 --- a/preact-emoji-rules/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-emoji-rules - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-emoji-rules) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-emoji-rules) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-emoji-rules preact-emoji-rules -cd preact-emoji-rules -npm install -npm run dev -``` diff --git a/preact-emoji-rules/index.html b/preact-emoji-rules/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-emoji-rules/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-emoji-rules/package.json b/preact-emoji-rules/package.json deleted file mode 100644 index ef6efa80d6..0000000000 --- a/preact-emoji-rules/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-emoji-rules", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-emoji-rules/src/App.tsx b/preact-emoji-rules/src/App.tsx deleted file mode 100644 index 1e4ef54fd6..0000000000 --- a/preact-emoji-rules/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/emoji-rules' - -export default function App() { - return -} diff --git a/preact-emoji-rules/src/app.css b/preact-emoji-rules/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-emoji-rules/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx b/preact-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx deleted file mode 100644 index 3b01b9885a..0000000000 --- a/preact-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/preact-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts deleted file mode 100644 index 5cac9cbc79..0000000000 --- a/preact-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineEnterRule } from 'prosekit/extensions/enter-rule' - -/** - * Converts the text before the text cursor into an emoji when pressing `Enter`. - */ -export function defineEmojiEnterRule() { - return defineEnterRule({ - regex: /:(apple|banana):$/, - handler: ({ match, from, to, state }) => { - const text = match[1] as 'apple' | 'banana' - const emoji = text === 'apple' ? '🍎' : '🍌' - return state.tr.replaceWith(from, to, state.schema.text(emoji)) - }, - }) -} diff --git a/preact-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/preact-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts deleted file mode 100644 index bc9bcb8412..0000000000 --- a/preact-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { defineEmojiEnterRule } from './emoji' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineEmojiEnterRule(), - definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/preact-emoji-rules/src/components/editor/examples/emoji-rules/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-emoji-rules/src/components/editor/examples/emoji-rules/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-emoji-rules/src/main.tsx b/preact-emoji-rules/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-emoji-rules/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-emoji-rules/tsconfig.app.json b/preact-emoji-rules/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-emoji-rules/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-emoji-rules/tsconfig.json b/preact-emoji-rules/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-emoji-rules/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-emoji-rules/tsconfig.node.json b/preact-emoji-rules/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-emoji-rules/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-emoji-rules/vite.config.ts b/preact-emoji-rules/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-emoji-rules/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-full/.gitignore b/preact-full/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-full/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-full/README.md b/preact-full/README.md deleted file mode 100644 index a755515e86..0000000000 --- a/preact-full/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-full - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-full) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-full) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-full preact-full -cd preact-full -npm install -npm run dev -``` diff --git a/preact-full/index.html b/preact-full/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-full/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-full/package.json b/preact-full/package.json deleted file mode 100644 index d76b85d81f..0000000000 --- a/preact-full/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-preact-full", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-full/src/App.tsx b/preact-full/src/App.tsx deleted file mode 100644 index c93bd3a429..0000000000 --- a/preact-full/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/full' - -export default function App() { - return -} diff --git a/preact-full/src/app.css b/preact-full/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-full/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-full/src/components/editor/examples/full/editor.tsx b/preact-full/src/components/editor/examples/full/editor.tsx deleted file mode 100644 index 2a2cc247e9..0000000000 --- a/preact-full/src/components/editor/examples/full/editor.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-full' -import { tags } from '../../sample/sample-tag-data' -import { sampleUploader } from '../../sample/sample-uploader' -import { users } from '../../sample/sample-user-data' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' -import { InlineMenu } from '../../ui/inline-menu' -import { SlashMenu } from '../../ui/slash-menu' -import { TableHandle } from '../../ui/table-handle' -import { TagMenu } from '../../ui/tag-menu' -import { Toolbar } from '../../ui/toolbar' -import { UserMenu } from '../../ui/user-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
- - - - - - - -
-
-
- ) -} diff --git a/preact-full/src/components/editor/examples/full/extension.ts b/preact-full/src/components/editor/examples/full/extension.ts deleted file mode 100644 index 5fc2f60685..0000000000 --- a/preact-full/src/components/editor/examples/full/extension.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineImageUploadHandler } from 'prosekit/extensions/image' -import { defineMath } from 'prosekit/extensions/math' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' -import { sampleUploader } from '../../sample/sample-uploader' -import { defineCodeBlockView } from '../../ui/code-block-view' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - defineMention(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - defineCodeBlockShiki(), - defineHorizontalRule(), - defineCodeBlockView(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-full/src/components/editor/examples/full/index.ts b/preact-full/src/components/editor/examples/full/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-full/src/components/editor/examples/full/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-full/src/components/editor/sample/katex.ts b/preact-full/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/preact-full/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/preact-full/src/components/editor/sample/sample-doc-full.ts b/preact-full/src/components/editor/sample/sample-doc-full.ts deleted file mode 100644 index 13e49b634d..0000000000 --- a/preact-full/src/components/editor/sample/sample-doc-full.ts +++ /dev/null @@ -1,442 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'The editor that thinks like you' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', - }, - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'writing without barriers', - }, - { type: 'text', text: '.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Text that shines.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Make your words ' }, - { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, - { type: 'text', text: ', or ' }, - { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, - { type: 'text', text: '. Add ' }, - { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, - { type: 'text', text: ' that stands out. Create ' }, - { - type: 'text', - marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], - text: 'links', - }, - { type: 'text', text: ' that connect.' }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Select any text to format it. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '@' }, - { type: 'text', text: ' to mention ' }, - { - type: 'mention', - attrs: { id: '39', value: '@someone', kind: 'user' }, - }, - { type: 'text', text: ' or ' }, - { type: 'text', marks: [{ type: 'code' }], text: '#' }, - { type: 'text', text: ' for ' }, - { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, - { type: 'text', text: '. Press ' }, - { type: 'text', marks: [{ type: 'code' }], text: '/' }, - { type: 'text', text: " and discover what's possible." }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Lists that organize.' }], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Bullet points that guide thoughts' }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Nested lists for complex ideas' }], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sub-points flow naturally' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Tasks that focus' }], - }, - { - type: 'list', - attrs: { kind: 'task', order: null, checked: true, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Done feels good' }], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Todo drives action' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Numbered steps' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sequential thinking' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Clear progress' }], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Code that inspires.' }], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Images that captivate.' }], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/season/320x240/107', - }, - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the handle in the bottom right corner to resize.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Tables that structure.' }], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'Feature', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'How to use', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Format text' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Select and choose' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Perfect styling' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Add mentions' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Type @ and name' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Connected ideas' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Insert anything' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Press / for menu' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Endless possibilities' }], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Math that renders.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Inline math like ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' appears within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Quotes that inspire.' }], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: '"This is not just an editor. This is how writing should feel."', - }, - ], - }, - ], - }, - { type: 'horizontalRule' }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Start typing. Everything else just flows.' }, - ], - }, - ], -} diff --git a/preact-full/src/components/editor/sample/sample-tag-data.ts b/preact-full/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/preact-full/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/preact-full/src/components/editor/sample/sample-uploader.ts b/preact-full/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/preact-full/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/preact-full/src/components/editor/sample/sample-user-data.ts b/preact-full/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/preact-full/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/preact-full/src/components/editor/ui/block-handle/block-handle.tsx b/preact-full/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 8f5fe62e40..0000000000 --- a/preact-full/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/preact/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/preact-full/src/components/editor/ui/block-handle/index.ts b/preact-full/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/preact-full/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/preact-full/src/components/editor/ui/button/button.tsx b/preact-full/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-full/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-full/src/components/editor/ui/button/index.ts b/preact-full/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-full/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-full/src/components/editor/ui/code-block-view/code-block-view.tsx b/preact-full/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index 59e33d3ded..0000000000 --- a/preact-full/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import type { JSX } from 'preact' -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { PreactNodeViewProps } from 'prosekit/preact' - -export default function CodeBlockView(props: PreactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language || '' - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - const handleChange = (event: JSX.TargetedEvent) => { - setLanguage(event.currentTarget.value) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/preact-full/src/components/editor/ui/code-block-view/index.ts b/preact-full/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index 247f963d7e..0000000000
--- a/preact-full/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  definePreactNodeView,
-  type PreactNodeViewComponent,
-} from 'prosekit/preact'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return definePreactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies PreactNodeViewComponent,
-  })
-}
diff --git a/preact-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/preact-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
deleted file mode 100644
index 6ace546a12..0000000000
--- a/preact-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { DropIndicator as BaseDropIndicator } from 'prosekit/preact/drop-indicator'
-
-export default function DropIndicator() {
-  return 
-}
diff --git a/preact-full/src/components/editor/ui/drop-indicator/index.ts b/preact-full/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index f8fb7139c4..0000000000
--- a/preact-full/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator'
diff --git a/preact-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
deleted file mode 100644
index 764667a8c0..0000000000
--- a/preact-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-import type { ComponentChild, JSX } from 'preact'
-import { useId, useState } from 'preact/hooks'
-import type { Uploader } from 'prosekit/extensions/file'
-import type { ImageExtension } from 'prosekit/extensions/image'
-import { useEditor } from 'prosekit/preact'
-import {
-  PopoverPopup,
-  PopoverPositioner,
-  PopoverRoot,
-  PopoverTrigger,
-} from 'prosekit/preact/popover'
-import type { OpenChangeEvent } from 'prosekit/web/popover'
-
-import { Button } from '../button'
-
-export default function ImageUploadPopover(props: {
-  uploader: Uploader
-  tooltip: string
-  disabled: boolean
-  children: ComponentChild
-}) {
-  const [open, setOpen] = useState(false)
-  const [url, setUrl] = useState('')
-  const [file, setFile] = useState(null)
-  const ariaId = useId()
-
-  const editor = useEditor()
-
-  const handleFileChange = (
-    event: JSX.TargetedEvent,
-  ) => {
-    const file = event.currentTarget.files?.[0]
-
-    if (file) {
-      setFile(file)
-      setUrl('')
-    } else {
-      setFile(null)
-    }
-  }
-
-  const handleUrlChange = (
-    event: JSX.TargetedEvent,
-  ) => {
-    const url = event.currentTarget.value
-
-    if (url) {
-      setUrl(url)
-      setFile(null)
-    } else {
-      setUrl('')
-    }
-  }
-
-  const deferResetState = () => {
-    setTimeout(() => {
-      setUrl('')
-      setFile(null)
-    }, 300)
-  }
-
-  const handleSubmit = () => {
-    if (url) {
-      editor.commands.insertImage({ src: url })
-    } else if (file) {
-      editor.commands.uploadImage({ file, uploader: props.uploader })
-    }
-    setOpen(false)
-    deferResetState()
-  }
-
-  const handleOpenChange = (event: OpenChangeEvent) => {
-    if (!event.detail) {
-      deferResetState()
-    }
-    setOpen(event.detail)
-  }
-
-  return (
-    
-      
-        
-      
-
-      
-        
-          {file ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? (
-            
-          ) : null}
-
-          {file ? (
-            
-          ) : null}
-        
-      
-    
-  )
-}
diff --git a/preact-full/src/components/editor/ui/image-upload-popover/index.ts b/preact-full/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index 5d49d873ce..0000000000
--- a/preact-full/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/preact-full/src/components/editor/ui/image-view/image-view.tsx b/preact-full/src/components/editor/ui/image-view/image-view.tsx
deleted file mode 100644
index 1b83843d1a..0000000000
--- a/preact-full/src/components/editor/ui/image-view/image-view.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-import type { JSX } from 'preact'
-import { useEffect, useState } from 'preact/hooks'
-import { UploadTask } from 'prosekit/extensions/file'
-import type { ImageAttrs } from 'prosekit/extensions/image'
-import type { PreactNodeViewProps } from 'prosekit/preact'
-import { ResizableHandle, ResizableRoot } from 'prosekit/preact/resizable'
-
-export default function ImageView(props: PreactNodeViewProps) {
-  const attrs = props.node.attrs as ImageAttrs
-  const url = attrs.src || ''
-  const uploading = url.startsWith('blob:')
-
-  const [aspectRatio, setAspectRatio] = useState()
-  const [error, setError] = useState()
-  const [progress, setProgress] = useState(0)
-
-  useEffect(() => {
-    if (!uploading) return
-
-    const uploadTask = UploadTask.get(url)
-    if (!uploadTask) return
-
-    let canceled = false
-
-    uploadTask.finished.catch((error) => {
-      if (canceled) return
-      setError(String(error))
-    })
-    const unsubscribeProgress = uploadTask.subscribeProgress(
-      ({ loaded, total }) => {
-        if (canceled) return
-        setProgress(total ? loaded / total : 0)
-      },
-    )
-
-    return () => {
-      canceled = true
-      unsubscribeProgress()
-    }
-  }, [url, uploading])
-
-  const handleImageLoad = (
-    event: JSX.TargetedEvent,
-  ) => {
-    const img = event.currentTarget
-    const { naturalWidth, naturalHeight } = img
-    const ratio = naturalWidth / naturalHeight
-    if (ratio && Number.isFinite(ratio)) {
-      setAspectRatio(ratio)
-    }
-    if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) {
-      props.setAttrs({ width: naturalWidth, height: naturalHeight })
-    }
-  }
-
-  return (
-     props.setAttrs(event.detail)}
-      data-selected={props.selected ? '' : undefined}
-      className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid"
-    >
-      {url && !error && (
-        upload preview
-      )}
-      {uploading && !error && (
-        
-
-
{Math.round(progress * 100)}%
-
- )} - {error && ( -
-
-
- Failed to upload image -
-
- )} - -
-
-
- ) -} diff --git a/preact-full/src/components/editor/ui/image-view/index.ts b/preact-full/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index 2b8200267d..0000000000 --- a/preact-full/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - definePreactNodeView, - type PreactNodeViewComponent, -} from 'prosekit/preact' - -import ImageView from './image-view' - -export function defineImageView(): Extension { - return definePreactNodeView({ - name: 'image', - component: ImageView satisfies PreactNodeViewComponent, - }) -} diff --git a/preact-full/src/components/editor/ui/inline-menu/index.ts b/preact-full/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/preact-full/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/preact-full/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-full/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index a014b74f57..0000000000 --- a/preact-full/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -import type { JSX } from 'preact' -import { useState } from 'preact/hooks' -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/preact' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/preact/inline-popover' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - const handleSubmit = ( - event: JSX.TargetedEvent, - ) => { - event.preventDefault() - const href = event.currentTarget.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
- -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/preact-full/src/components/editor/ui/slash-menu/index.ts b/preact-full/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/preact-full/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/preact-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/preact-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index bedf7d7ebb..0000000000 --- a/preact-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { AutocompleteEmpty } from 'prosekit/preact/autocomplete' - -export default function SlashMenuEmpty() { - return ( - - No results - - ) -} diff --git a/preact-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/preact-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 1bb81f797d..0000000000 --- a/preact-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { AutocompleteItem } from 'prosekit/preact/autocomplete' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}) { - return ( - - {props.label} - {props.kbd && ( - - {props.kbd} - - )} - - ) -} diff --git a/preact-full/src/components/editor/ui/slash-menu/slash-menu.tsx b/preact-full/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index 092327c28e..0000000000 --- a/preact-full/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/preact' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/preact/autocomplete' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor.commands.setParagraph()} - /> - - editor.commands.setHeading({ level: 1 })} - /> - - editor.commands.setHeading({ level: 2 })} - /> - - editor.commands.setHeading({ level: 3 })} - /> - - editor.commands.wrapInList({ kind: 'bullet' })} - /> - - editor.commands.wrapInList({ kind: 'ordered' })} - /> - - editor.commands.wrapInList({ kind: 'task' })} - /> - - editor.commands.wrapInList({ kind: 'toggle' })} - /> - - editor.commands.setBlockquote()} - /> - - editor.commands.insertTable({ row: 3, col: 3 })} - /> - - editor.commands.insertHorizontalRule()} - /> - - editor.commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/preact-full/src/components/editor/ui/table-handle/index.ts b/preact-full/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/preact-full/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/preact-full/src/components/editor/ui/table-handle/table-handle.tsx b/preact-full/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index 6182b185c6..0000000000 --- a/preact-full/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/preact' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/preact/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/preact/table-handle' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props) { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - {state.addTableColumnBefore.canExec && ( - - Insert Left - - )} - {state.addTableColumnAfter.canExec && ( - - Insert Right - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableColumn.canExec && ( - - Delete Column - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
- - - - -
-
- - - {state.addTableRowAbove.canExec && ( - - Insert Above - - )} - {state.addTableRowBelow.canExec && ( - - Insert Below - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableRow.canExec && ( - - Delete Row - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
-
- ) -} diff --git a/preact-full/src/components/editor/ui/tag-menu/index.ts b/preact-full/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index d344b33a70..0000000000 --- a/preact-full/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu' diff --git a/preact-full/src/components/editor/ui/tag-menu/tag-menu.tsx b/preact-full/src/components/editor/ui/tag-menu/tag-menu.tsx deleted file mode 100644 index 00b3e4b085..0000000000 --- a/preact-full/src/components/editor/ui/tag-menu/tag-menu.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/preact' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/preact/autocomplete' - -const regex = /#[\da-z]*$/i - -export default function TagMenu(props: { - tags: { id: number; label: string }[] -}) { - const editor = useEditor>() - - const handleTagInsert = (id: number, label: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '#' + label, - kind: 'tag', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - - - -
- - No results - - - {props.tags.map((tag) => ( - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - ))} -
-
-
-
- ) -} diff --git a/preact-full/src/components/editor/ui/toolbar/index.ts b/preact-full/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-full/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-full/src/components/editor/ui/toolbar/toolbar.tsx b/preact-full/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-full/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-full/src/components/editor/ui/user-menu/index.ts b/preact-full/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/preact-full/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/preact-full/src/components/editor/ui/user-menu/user-menu.tsx b/preact-full/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 39b78adbde..0000000000 --- a/preact-full/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/preact' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/preact/autocomplete' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}) { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - {props.users.map((user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - ))} -
-
-
-
- ) -} diff --git a/preact-full/src/main.tsx b/preact-full/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-full/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-full/tsconfig.app.json b/preact-full/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-full/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-full/tsconfig.json b/preact-full/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-full/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-full/tsconfig.node.json b/preact-full/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-full/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-full/vite.config.ts b/preact-full/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-full/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-gap-cursor/.gitignore b/preact-gap-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-gap-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-gap-cursor/README.md b/preact-gap-cursor/README.md deleted file mode 100644 index 62c34e646b..0000000000 --- a/preact-gap-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-gap-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-gap-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-gap-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-gap-cursor preact-gap-cursor -cd preact-gap-cursor -npm install -npm run dev -``` diff --git a/preact-gap-cursor/index.html b/preact-gap-cursor/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-gap-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-gap-cursor/package.json b/preact-gap-cursor/package.json deleted file mode 100644 index 8b316bfbeb..0000000000 --- a/preact-gap-cursor/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-gap-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-gap-cursor/src/App.tsx b/preact-gap-cursor/src/App.tsx deleted file mode 100644 index ed7e74417e..0000000000 --- a/preact-gap-cursor/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/gap-cursor' - -export default function App() { - return -} diff --git a/preact-gap-cursor/src/app.css b/preact-gap-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-gap-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx b/preact-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx deleted file mode 100644 index ddb07f62cb..0000000000 --- a/preact-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-gap-cursor' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - return createEditor({ extension: defineExtension(), defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/preact-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts deleted file mode 100644 index 599497170d..0000000000 --- a/preact-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineGapCursor(), - defineImage(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/preact-gap-cursor/src/components/editor/examples/gap-cursor/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-gap-cursor/src/components/editor/examples/gap-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/preact-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts deleted file mode 100644 index e40ee2a83b..0000000000 --- a/preact-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - ], -} diff --git a/preact-gap-cursor/src/main.tsx b/preact-gap-cursor/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-gap-cursor/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-gap-cursor/tsconfig.app.json b/preact-gap-cursor/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-gap-cursor/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-gap-cursor/tsconfig.json b/preact-gap-cursor/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-gap-cursor/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-gap-cursor/tsconfig.node.json b/preact-gap-cursor/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-gap-cursor/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-gap-cursor/vite.config.ts b/preact-gap-cursor/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-gap-cursor/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-hard-break/.gitignore b/preact-hard-break/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-hard-break/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-hard-break/README.md b/preact-hard-break/README.md deleted file mode 100644 index d0c6428d7b..0000000000 --- a/preact-hard-break/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-hard-break - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-hard-break) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-hard-break) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-hard-break preact-hard-break -cd preact-hard-break -npm install -npm run dev -``` diff --git a/preact-hard-break/index.html b/preact-hard-break/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-hard-break/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-hard-break/package.json b/preact-hard-break/package.json deleted file mode 100644 index bf1dc4403d..0000000000 --- a/preact-hard-break/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-hard-break", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-hard-break/src/App.tsx b/preact-hard-break/src/App.tsx deleted file mode 100644 index db3ea90c2a..0000000000 --- a/preact-hard-break/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/hard-break' - -export default function App() { - return -} diff --git a/preact-hard-break/src/app.css b/preact-hard-break/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-hard-break/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-hard-break/src/components/editor/examples/hard-break/editor.tsx b/preact-hard-break/src/components/editor/examples/hard-break/editor.tsx deleted file mode 100644 index 7a5fdb265c..0000000000 --- a/preact-hard-break/src/components/editor/examples/hard-break/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-hard-break' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-hard-break/src/components/editor/examples/hard-break/extension.ts b/preact-hard-break/src/components/editor/examples/hard-break/extension.ts deleted file mode 100644 index cad2881056..0000000000 --- a/preact-hard-break/src/components/editor/examples/hard-break/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHardBreak } from 'prosekit/extensions/hard-break' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHardBreak(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-hard-break/src/components/editor/examples/hard-break/index.ts b/preact-hard-break/src/components/editor/examples/hard-break/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-hard-break/src/components/editor/examples/hard-break/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-hard-break/src/components/editor/examples/hard-break/toolbar.tsx b/preact-hard-break/src/components/editor/examples/hard-break/toolbar.tsx deleted file mode 100644 index c8ee2d5b4f..0000000000 --- a/preact-hard-break/src/components/editor/examples/hard-break/toolbar.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - hardBreak: { - canExec: editor.commands.insertHardBreak.canExec(), - command: () => editor.commands.insertHardBreak(), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/preact-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/preact-hard-break/src/components/editor/sample/sample-doc-hard-break.ts deleted file mode 100644 index e1c9786b72..0000000000 --- a/preact-hard-break/src/components/editor/sample/sample-doc-hard-break.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: "O'er all the hilltops", - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Is quiet now,', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'In all the treetops', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hearest thou', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hardly a breath;', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'The birds are asleep in the trees:', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Wait, soon like these', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Thou too shalt rest.', - }, - { - type: 'hardBreak', - }, - ], - }, - ], -} diff --git a/preact-hard-break/src/components/editor/ui/button/button.tsx b/preact-hard-break/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-hard-break/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-hard-break/src/components/editor/ui/button/index.ts b/preact-hard-break/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-hard-break/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-hard-break/src/main.tsx b/preact-hard-break/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-hard-break/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-hard-break/tsconfig.app.json b/preact-hard-break/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-hard-break/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-hard-break/tsconfig.json b/preact-hard-break/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-hard-break/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-hard-break/tsconfig.node.json b/preact-hard-break/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-hard-break/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-hard-break/vite.config.ts b/preact-hard-break/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-hard-break/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-heading/.gitignore b/preact-heading/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-heading/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-heading/README.md b/preact-heading/README.md deleted file mode 100644 index 521ea11cee..0000000000 --- a/preact-heading/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-heading - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-heading) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-heading) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-heading preact-heading -cd preact-heading -npm install -npm run dev -``` diff --git a/preact-heading/index.html b/preact-heading/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-heading/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-heading/package.json b/preact-heading/package.json deleted file mode 100644 index cbeea72dc0..0000000000 --- a/preact-heading/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-heading", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-heading/src/App.tsx b/preact-heading/src/App.tsx deleted file mode 100644 index c70e72d05f..0000000000 --- a/preact-heading/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/heading' - -export default function App() { - return -} diff --git a/preact-heading/src/app.css b/preact-heading/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-heading/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-heading/src/components/editor/examples/heading/editor.tsx b/preact-heading/src/components/editor/examples/heading/editor.tsx deleted file mode 100644 index dfd25406b3..0000000000 --- a/preact-heading/src/components/editor/examples/heading/editor.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-heading' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - return createEditor({ extension: defineExtension(), defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-heading/src/components/editor/examples/heading/extension.ts b/preact-heading/src/components/editor/examples/heading/extension.ts deleted file mode 100644 index e4f8e6ace0..0000000000 --- a/preact-heading/src/components/editor/examples/heading/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHeading(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-heading/src/components/editor/examples/heading/index.ts b/preact-heading/src/components/editor/examples/heading/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-heading/src/components/editor/examples/heading/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-heading/src/components/editor/sample/sample-doc-heading.ts b/preact-heading/src/components/editor/sample/sample-doc-heading.ts deleted file mode 100644 index 210497e633..0000000000 --- a/preact-heading/src/components/editor/sample/sample-doc-heading.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'H1' }], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'H2' }], - }, - { - type: 'heading', - attrs: { level: 3 }, - content: [{ type: 'text', text: 'H3' }], - }, - { type: 'paragraph', content: [] }, - ], -} diff --git a/preact-heading/src/components/editor/ui/button/button.tsx b/preact-heading/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-heading/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-heading/src/components/editor/ui/button/index.ts b/preact-heading/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-heading/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-heading/src/components/editor/ui/image-upload-popover/index.ts b/preact-heading/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-heading/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-heading/src/components/editor/ui/toolbar/index.ts b/preact-heading/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-heading/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-heading/src/components/editor/ui/toolbar/toolbar.tsx b/preact-heading/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-heading/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-heading/src/main.tsx b/preact-heading/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-heading/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-heading/tsconfig.app.json b/preact-heading/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-heading/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-heading/tsconfig.json b/preact-heading/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-heading/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-heading/tsconfig.node.json b/preact-heading/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-heading/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-heading/vite.config.ts b/preact-heading/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-heading/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-highlight/.gitignore b/preact-highlight/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-highlight/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-highlight/README.md b/preact-highlight/README.md deleted file mode 100644 index 72e9564ce9..0000000000 --- a/preact-highlight/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-highlight - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-highlight) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-highlight) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-highlight preact-highlight -cd preact-highlight -npm install -npm run dev -``` diff --git a/preact-highlight/index.html b/preact-highlight/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-highlight/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-highlight/package.json b/preact-highlight/package.json deleted file mode 100644 index b977f4c710..0000000000 --- a/preact-highlight/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-highlight", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-highlight/src/App.tsx b/preact-highlight/src/App.tsx deleted file mode 100644 index 2509b001f7..0000000000 --- a/preact-highlight/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/highlight' - -export default function App() { - return -} diff --git a/preact-highlight/src/app.css b/preact-highlight/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-highlight/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-highlight/src/components/editor/examples/highlight/editor.tsx b/preact-highlight/src/components/editor/examples/highlight/editor.tsx deleted file mode 100644 index fd63d28e8c..0000000000 --- a/preact-highlight/src/components/editor/examples/highlight/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-highlight' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-highlight/src/components/editor/examples/highlight/extension.ts b/preact-highlight/src/components/editor/examples/highlight/extension.ts deleted file mode 100644 index abc131c3be..0000000000 --- a/preact-highlight/src/components/editor/examples/highlight/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHighlight } from 'prosekit/extensions/highlight' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHighlight(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-highlight/src/components/editor/examples/highlight/index.ts b/preact-highlight/src/components/editor/examples/highlight/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-highlight/src/components/editor/examples/highlight/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-highlight/src/components/editor/examples/highlight/toolbar.tsx b/preact-highlight/src/components/editor/examples/highlight/toolbar.tsx deleted file mode 100644 index 66b03a127f..0000000000 --- a/preact-highlight/src/components/editor/examples/highlight/toolbar.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - highlight: { - isActive: editor.marks.highlight.isActive(), - canExec: editor.commands.toggleHighlight.canExec(), - command: () => editor.commands.toggleHighlight(), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/preact-highlight/src/components/editor/sample/sample-doc-highlight.ts b/preact-highlight/src/components/editor/sample/sample-doc-highlight.ts deleted file mode 100644 index 0de1a1f7b2..0000000000 --- a/preact-highlight/src/components/editor/sample/sample-doc-highlight.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'highlight', - }, - ], - text: 'This is highlighted text', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/preact-highlight/src/components/editor/ui/button/button.tsx b/preact-highlight/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-highlight/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-highlight/src/components/editor/ui/button/index.ts b/preact-highlight/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-highlight/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-highlight/src/main.tsx b/preact-highlight/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-highlight/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-highlight/tsconfig.app.json b/preact-highlight/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-highlight/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-highlight/tsconfig.json b/preact-highlight/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-highlight/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-highlight/tsconfig.node.json b/preact-highlight/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-highlight/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-highlight/vite.config.ts b/preact-highlight/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-highlight/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-horizontal-rule/.gitignore b/preact-horizontal-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-horizontal-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-horizontal-rule/README.md b/preact-horizontal-rule/README.md deleted file mode 100644 index 007b59f8ee..0000000000 --- a/preact-horizontal-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-horizontal-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-horizontal-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-horizontal-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-horizontal-rule preact-horizontal-rule -cd preact-horizontal-rule -npm install -npm run dev -``` diff --git a/preact-horizontal-rule/index.html b/preact-horizontal-rule/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-horizontal-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-horizontal-rule/package.json b/preact-horizontal-rule/package.json deleted file mode 100644 index 0e04aac6b7..0000000000 --- a/preact-horizontal-rule/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-horizontal-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-horizontal-rule/src/App.tsx b/preact-horizontal-rule/src/App.tsx deleted file mode 100644 index 974e387364..0000000000 --- a/preact-horizontal-rule/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/horizontal-rule' - -export default function App() { - return -} diff --git a/preact-horizontal-rule/src/app.css b/preact-horizontal-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-horizontal-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx deleted file mode 100644 index 47be0af302..0000000000 --- a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - return createEditor({ extension: defineExtension() }) - }, []) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts deleted file mode 100644 index 49b6121eeb..0000000000 --- a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHorizontalRule(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-horizontal-rule/src/components/editor/ui/button/button.tsx b/preact-horizontal-rule/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-horizontal-rule/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-horizontal-rule/src/components/editor/ui/button/index.ts b/preact-horizontal-rule/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-horizontal-rule/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/preact-horizontal-rule/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-horizontal-rule/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx b/preact-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-horizontal-rule/src/main.tsx b/preact-horizontal-rule/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-horizontal-rule/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-horizontal-rule/tsconfig.app.json b/preact-horizontal-rule/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-horizontal-rule/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-horizontal-rule/tsconfig.json b/preact-horizontal-rule/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-horizontal-rule/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-horizontal-rule/tsconfig.node.json b/preact-horizontal-rule/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-horizontal-rule/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-horizontal-rule/vite.config.ts b/preact-horizontal-rule/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-horizontal-rule/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-image-view/.gitignore b/preact-image-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-image-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-image-view/README.md b/preact-image-view/README.md deleted file mode 100644 index 11e4af847a..0000000000 --- a/preact-image-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-image-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-image-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-image-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-image-view preact-image-view -cd preact-image-view -npm install -npm run dev -``` diff --git a/preact-image-view/index.html b/preact-image-view/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-image-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-image-view/package.json b/preact-image-view/package.json deleted file mode 100644 index 9fdee631cc..0000000000 --- a/preact-image-view/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-image-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-image-view/src/App.tsx b/preact-image-view/src/App.tsx deleted file mode 100644 index 46ede58891..0000000000 --- a/preact-image-view/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/image-view' - -export default function App() { - return -} diff --git a/preact-image-view/src/app.css b/preact-image-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-image-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-image-view/src/components/editor/examples/image-view/editor.tsx b/preact-image-view/src/components/editor/examples/image-view/editor.tsx deleted file mode 100644 index 87f1aefb88..0000000000 --- a/preact-image-view/src/components/editor/examples/image-view/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-image' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-image-view/src/components/editor/examples/image-view/extension.ts b/preact-image-view/src/components/editor/examples/image-view/extension.ts deleted file mode 100644 index a21febf634..0000000000 --- a/preact-image-view/src/components/editor/examples/image-view/extension.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineImageUploadHandler } from 'prosekit/extensions/image' - -import { sampleUploader } from '../../sample/sample-uploader' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-image-view/src/components/editor/examples/image-view/index.ts b/preact-image-view/src/components/editor/examples/image-view/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-image-view/src/components/editor/examples/image-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-image-view/src/components/editor/sample/sample-doc-image.ts b/preact-image-view/src/components/editor/sample/sample-doc-image.ts deleted file mode 100644 index c97628339d..0000000000 --- a/preact-image-view/src/components/editor/sample/sample-doc-image.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Paste or drop an image to upload it.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/white/200x200/1', - width: 160, - height: 160, - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/640x360/42', - width: 240, - height: 135, - }, - }, - ], -} diff --git a/preact-image-view/src/components/editor/sample/sample-uploader.ts b/preact-image-view/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/preact-image-view/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/preact-image-view/src/components/editor/ui/image-view/image-view.tsx b/preact-image-view/src/components/editor/ui/image-view/image-view.tsx deleted file mode 100644 index 1b83843d1a..0000000000 --- a/preact-image-view/src/components/editor/ui/image-view/image-view.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import type { JSX } from 'preact' -import { useEffect, useState } from 'preact/hooks' -import { UploadTask } from 'prosekit/extensions/file' -import type { ImageAttrs } from 'prosekit/extensions/image' -import type { PreactNodeViewProps } from 'prosekit/preact' -import { ResizableHandle, ResizableRoot } from 'prosekit/preact/resizable' - -export default function ImageView(props: PreactNodeViewProps) { - const attrs = props.node.attrs as ImageAttrs - const url = attrs.src || '' - const uploading = url.startsWith('blob:') - - const [aspectRatio, setAspectRatio] = useState() - const [error, setError] = useState() - const [progress, setProgress] = useState(0) - - useEffect(() => { - if (!uploading) return - - const uploadTask = UploadTask.get(url) - if (!uploadTask) return - - let canceled = false - - uploadTask.finished.catch((error) => { - if (canceled) return - setError(String(error)) - }) - const unsubscribeProgress = uploadTask.subscribeProgress( - ({ loaded, total }) => { - if (canceled) return - setProgress(total ? loaded / total : 0) - }, - ) - - return () => { - canceled = true - unsubscribeProgress() - } - }, [url, uploading]) - - const handleImageLoad = ( - event: JSX.TargetedEvent, - ) => { - const img = event.currentTarget - const { naturalWidth, naturalHeight } = img - const ratio = naturalWidth / naturalHeight - if (ratio && Number.isFinite(ratio)) { - setAspectRatio(ratio) - } - if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) { - props.setAttrs({ width: naturalWidth, height: naturalHeight }) - } - } - - return ( - props.setAttrs(event.detail)} - data-selected={props.selected ? '' : undefined} - className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid" - > - {url && !error && ( - upload preview - )} - {uploading && !error && ( -
-
-
{Math.round(progress * 100)}%
-
- )} - {error && ( -
-
-
- Failed to upload image -
-
- )} - -
-
-
- ) -} diff --git a/preact-image-view/src/components/editor/ui/image-view/index.ts b/preact-image-view/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index 2b8200267d..0000000000 --- a/preact-image-view/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - definePreactNodeView, - type PreactNodeViewComponent, -} from 'prosekit/preact' - -import ImageView from './image-view' - -export function defineImageView(): Extension { - return definePreactNodeView({ - name: 'image', - component: ImageView satisfies PreactNodeViewComponent, - }) -} diff --git a/preact-image-view/src/main.tsx b/preact-image-view/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-image-view/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-image-view/tsconfig.app.json b/preact-image-view/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-image-view/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-image-view/tsconfig.json b/preact-image-view/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-image-view/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-image-view/tsconfig.node.json b/preact-image-view/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-image-view/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-image-view/vite.config.ts b/preact-image-view/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-image-view/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-inline-menu/.gitignore b/preact-inline-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-inline-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-inline-menu/README.md b/preact-inline-menu/README.md deleted file mode 100644 index 68bb759fbe..0000000000 --- a/preact-inline-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-inline-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-inline-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-inline-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-inline-menu preact-inline-menu -cd preact-inline-menu -npm install -npm run dev -``` diff --git a/preact-inline-menu/index.html b/preact-inline-menu/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-inline-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-inline-menu/package.json b/preact-inline-menu/package.json deleted file mode 100644 index 03c65e03cf..0000000000 --- a/preact-inline-menu/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-inline-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-inline-menu/src/App.tsx b/preact-inline-menu/src/App.tsx deleted file mode 100644 index 660285db3c..0000000000 --- a/preact-inline-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/inline-menu' - -export default function App() { - return -} diff --git a/preact-inline-menu/src/app.css b/preact-inline-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-inline-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-inline-menu/src/components/editor/examples/inline-menu/editor.tsx b/preact-inline-menu/src/components/editor/examples/inline-menu/editor.tsx deleted file mode 100644 index 47a9f7334d..0000000000 --- a/preact-inline-menu/src/components/editor/examples/inline-menu/editor.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-inline-menu' -import { InlineMenu } from '../../ui/inline-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - return createEditor({ extension: defineExtension(), defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/preact-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/preact-inline-menu/src/components/editor/examples/inline-menu/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/preact-inline-menu/src/components/editor/examples/inline-menu/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/preact-inline-menu/src/components/editor/examples/inline-menu/index.ts b/preact-inline-menu/src/components/editor/examples/inline-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-inline-menu/src/components/editor/examples/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/preact-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts deleted file mode 100644 index 62a5984cb0..0000000000 --- a/preact-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const loremText = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'Try to select some text', - }, - ], - }, - ...Array.from({ length: 10 }, () => ({ - type: 'paragraph' as const, - content: [ - { - type: 'text' as const, - text: loremText, - }, - ], - })), - ], -} diff --git a/preact-inline-menu/src/components/editor/ui/button/button.tsx b/preact-inline-menu/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-inline-menu/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-inline-menu/src/components/editor/ui/button/index.ts b/preact-inline-menu/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-inline-menu/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-inline-menu/src/components/editor/ui/inline-menu/index.ts b/preact-inline-menu/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/preact-inline-menu/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/preact-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index a014b74f57..0000000000 --- a/preact-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -import type { JSX } from 'preact' -import { useState } from 'preact/hooks' -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/preact' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/preact/inline-popover' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - const handleSubmit = ( - event: JSX.TargetedEvent, - ) => { - event.preventDefault() - const href = event.currentTarget.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
- -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/preact-inline-menu/src/main.tsx b/preact-inline-menu/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-inline-menu/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-inline-menu/tsconfig.app.json b/preact-inline-menu/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-inline-menu/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-inline-menu/tsconfig.json b/preact-inline-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-inline-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-inline-menu/tsconfig.node.json b/preact-inline-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-inline-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-inline-menu/vite.config.ts b/preact-inline-menu/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-inline-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-italic/.gitignore b/preact-italic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-italic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-italic/README.md b/preact-italic/README.md deleted file mode 100644 index bf98e2b49a..0000000000 --- a/preact-italic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-italic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-italic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-italic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-italic preact-italic -cd preact-italic -npm install -npm run dev -``` diff --git a/preact-italic/index.html b/preact-italic/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-italic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-italic/package.json b/preact-italic/package.json deleted file mode 100644 index 0d4afa3739..0000000000 --- a/preact-italic/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-italic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-italic/src/App.tsx b/preact-italic/src/App.tsx deleted file mode 100644 index 7ce968b449..0000000000 --- a/preact-italic/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/italic' - -export default function App() { - return -} diff --git a/preact-italic/src/app.css b/preact-italic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-italic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-italic/src/components/editor/examples/italic/editor.tsx b/preact-italic/src/components/editor/examples/italic/editor.tsx deleted file mode 100644 index 519ef5ddec..0000000000 --- a/preact-italic/src/components/editor/examples/italic/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-italic' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-italic/src/components/editor/examples/italic/extension.ts b/preact-italic/src/components/editor/examples/italic/extension.ts deleted file mode 100644 index a456b06aad..0000000000 --- a/preact-italic/src/components/editor/examples/italic/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineItalic(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-italic/src/components/editor/examples/italic/index.ts b/preact-italic/src/components/editor/examples/italic/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-italic/src/components/editor/examples/italic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-italic/src/components/editor/sample/sample-doc-italic.ts b/preact-italic/src/components/editor/sample/sample-doc-italic.ts deleted file mode 100644 index fb99415b2c..0000000000 --- a/preact-italic/src/components/editor/sample/sample-doc-italic.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/preact-italic/src/components/editor/ui/button/button.tsx b/preact-italic/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-italic/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-italic/src/components/editor/ui/button/index.ts b/preact-italic/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-italic/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-italic/src/components/editor/ui/image-upload-popover/index.ts b/preact-italic/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-italic/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-italic/src/components/editor/ui/toolbar/index.ts b/preact-italic/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-italic/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-italic/src/components/editor/ui/toolbar/toolbar.tsx b/preact-italic/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-italic/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-italic/src/main.tsx b/preact-italic/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-italic/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-italic/tsconfig.app.json b/preact-italic/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-italic/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-italic/tsconfig.json b/preact-italic/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-italic/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-italic/tsconfig.node.json b/preact-italic/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-italic/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-italic/vite.config.ts b/preact-italic/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-italic/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-katex/.gitignore b/preact-katex/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-katex/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-katex/README.md b/preact-katex/README.md deleted file mode 100644 index ec9783e8d1..0000000000 --- a/preact-katex/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-katex - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-katex) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-katex) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-katex preact-katex -cd preact-katex -npm install -npm run dev -``` diff --git a/preact-katex/index.html b/preact-katex/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-katex/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-katex/package.json b/preact-katex/package.json deleted file mode 100644 index 226b66e563..0000000000 --- a/preact-katex/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-preact-katex", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.47", - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-katex/src/App.tsx b/preact-katex/src/App.tsx deleted file mode 100644 index 2a28c7c7d7..0000000000 --- a/preact-katex/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/katex' - -export default function App() { - return -} diff --git a/preact-katex/src/app.css b/preact-katex/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-katex/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-katex/src/components/editor/examples/katex/editor.tsx b/preact-katex/src/components/editor/examples/katex/editor.tsx deleted file mode 100644 index 89009d34a9..0000000000 --- a/preact-katex/src/components/editor/examples/katex/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-tex' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-katex/src/components/editor/examples/katex/extension.ts b/preact-katex/src/components/editor/examples/katex/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/preact-katex/src/components/editor/examples/katex/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-katex/src/components/editor/examples/katex/index.ts b/preact-katex/src/components/editor/examples/katex/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-katex/src/components/editor/examples/katex/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-katex/src/components/editor/sample/katex.ts b/preact-katex/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/preact-katex/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/preact-katex/src/components/editor/sample/sample-doc-tex.ts b/preact-katex/src/components/editor/sample/sample-doc-tex.ts deleted file mode 100644 index 21ccf3e94e..0000000000 --- a/preact-katex/src/components/editor/sample/sample-doc-tex.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Inline equations' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Block equations' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: 'The Gaussian integral:' }], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - ], -} diff --git a/preact-katex/src/main.tsx b/preact-katex/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-katex/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-katex/tsconfig.app.json b/preact-katex/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-katex/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-katex/tsconfig.json b/preact-katex/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-katex/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-katex/tsconfig.node.json b/preact-katex/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-katex/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-katex/vite.config.ts b/preact-katex/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-katex/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-keymap/.gitignore b/preact-keymap/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-keymap/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-keymap/README.md b/preact-keymap/README.md deleted file mode 100644 index a5ef706978..0000000000 --- a/preact-keymap/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-keymap - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-keymap) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-keymap) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-keymap preact-keymap -cd preact-keymap -npm install -npm run dev -``` diff --git a/preact-keymap/index.html b/preact-keymap/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-keymap/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-keymap/package.json b/preact-keymap/package.json deleted file mode 100644 index f0b705a45a..0000000000 --- a/preact-keymap/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-keymap", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-keymap/src/App.tsx b/preact-keymap/src/App.tsx deleted file mode 100644 index da3b6ebb09..0000000000 --- a/preact-keymap/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/keymap' - -export default function App() { - return -} diff --git a/preact-keymap/src/app.css b/preact-keymap/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-keymap/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-keymap/src/components/editor/examples/keymap/editor.tsx b/preact-keymap/src/components/editor/examples/keymap/editor.tsx deleted file mode 100644 index 18982a10fe..0000000000 --- a/preact-keymap/src/components/editor/examples/keymap/editor.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useCallback, useMemo, useState } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - const [submissions, setSubmissions] = useState([]) - - const pushSubmission = useCallback( - (hotkey: string) => { - const docString = JSON.stringify(editor.getDocJSON()) - const submission = `${new Date().toISOString()}\t${hotkey}\n${docString}` - setSubmissions((prev) => [...prev, submission]) - }, - [editor], - ) - - return ( - -
- -
-
-
-
-
- Submit Records -
    - {submissions.map((submission, index) => ( -
  1. -
    {submission}
    -
  2. - ))} -
- {submissions.length === 0 &&
No submissions yet
} -
-
- ) -} diff --git a/preact-keymap/src/components/editor/examples/keymap/extension.ts b/preact-keymap/src/components/editor/examples/keymap/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/preact-keymap/src/components/editor/examples/keymap/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/preact-keymap/src/components/editor/examples/keymap/index.ts b/preact-keymap/src/components/editor/examples/keymap/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-keymap/src/components/editor/examples/keymap/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-keymap/src/components/editor/examples/keymap/toolbar.tsx b/preact-keymap/src/components/editor/examples/keymap/toolbar.tsx deleted file mode 100644 index 59664071d7..0000000000 --- a/preact-keymap/src/components/editor/examples/keymap/toolbar.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { useState } from 'preact/hooks' - -import { Button } from '../../ui/button' - -import { useSubmitKeymap } from './use-submit-keymap' - -export default function Toolbar(props: { onSubmit: (hotkey: string) => void }) { - const [hotkey, setHotkey] = useState<'Shift-Enter' | 'Enter'>('Shift-Enter') - useSubmitKeymap(hotkey, props.onSubmit) - - return ( -
- - - -
- ) -} diff --git a/preact-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts b/preact-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts deleted file mode 100644 index 4f10405e56..0000000000 --- a/preact-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { useMemo } from 'preact/hooks' -import type { Keymap } from 'prosekit/core' -import { useKeymap } from 'prosekit/preact' - -export function useSubmitKeymap( - hotkey: 'Shift-Enter' | 'Enter', - onSubmit: (hotkey: string) => void, -) { - const keymap: Keymap = useMemo(() => { - return { - [hotkey]: () => { - onSubmit(hotkey) - return true - }, - } - }, [hotkey, onSubmit]) - - useKeymap(keymap) -} diff --git a/preact-keymap/src/components/editor/ui/button/button.tsx b/preact-keymap/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-keymap/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-keymap/src/components/editor/ui/button/index.ts b/preact-keymap/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-keymap/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-keymap/src/main.tsx b/preact-keymap/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-keymap/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-keymap/tsconfig.app.json b/preact-keymap/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-keymap/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-keymap/tsconfig.json b/preact-keymap/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-keymap/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-keymap/tsconfig.node.json b/preact-keymap/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-keymap/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-keymap/vite.config.ts b/preact-keymap/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-keymap/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-link-mark-view/.gitignore b/preact-link-mark-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-link-mark-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-link-mark-view/README.md b/preact-link-mark-view/README.md deleted file mode 100644 index 34a7cee8f0..0000000000 --- a/preact-link-mark-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-link-mark-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-link-mark-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-link-mark-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-link-mark-view preact-link-mark-view -cd preact-link-mark-view -npm install -npm run dev -``` diff --git a/preact-link-mark-view/index.html b/preact-link-mark-view/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-link-mark-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-link-mark-view/package.json b/preact-link-mark-view/package.json deleted file mode 100644 index e5bc864d38..0000000000 --- a/preact-link-mark-view/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-link-mark-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-link-mark-view/src/App.tsx b/preact-link-mark-view/src/App.tsx deleted file mode 100644 index 8a8685678d..0000000000 --- a/preact-link-mark-view/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/link-mark-view' - -export default function App() { - return -} diff --git a/preact-link-mark-view/src/app.css b/preact-link-mark-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-link-mark-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx b/preact-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx deleted file mode 100644 index 0d1fb8a3e7..0000000000 --- a/preact-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-link-mark-view' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/preact-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts deleted file mode 100644 index c9c2d7f7c1..0000000000 --- a/preact-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePreactMarkView } from 'prosekit/preact' - -import LinkView from './link-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePreactMarkView({ - name: 'link', - component: LinkView, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/preact-link-mark-view/src/components/editor/examples/link-mark-view/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-link-mark-view/src/components/editor/examples/link-mark-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx b/preact-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx deleted file mode 100644 index 14de85477b..0000000000 --- a/preact-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { useEffect, useState } from 'preact/hooks' -import type { PreactMarkViewProps } from 'prosekit/preact' - -const colors = [ - '#f06292', - '#ba68c8', - '#9575cd', - '#7986cb', - '#64b5f6', - '#4fc3f7', - '#4dd0e1', - '#4db6ac', - '#81c784', - '#aed581', - '#ffb74d', - '#ffa726', - '#ff8a65', - '#d4e157', - '#ffd54f', - '#ffecb3', -] as const - -function pickRandomColor() { - return colors[Math.floor(Math.random() * colors.length)] -} - -export default function Link(props: PreactMarkViewProps) { - const [color, setColor] = useState(colors[0]) - const href = props.mark.attrs.href as string - - useEffect(() => { - const interval = setInterval(() => { - setColor(pickRandomColor()) - }, 1000) - return () => clearInterval(interval) - }, []) - - return ( - - ) -} diff --git a/preact-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/preact-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts deleted file mode 100644 index 57abd09dd6..0000000000 --- a/preact-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is a link that changes color every second: ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/preact-link-mark-view/src/main.tsx b/preact-link-mark-view/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-link-mark-view/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-link-mark-view/tsconfig.app.json b/preact-link-mark-view/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-link-mark-view/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-link-mark-view/tsconfig.json b/preact-link-mark-view/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-link-mark-view/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-link-mark-view/tsconfig.node.json b/preact-link-mark-view/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-link-mark-view/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-link-mark-view/vite.config.ts b/preact-link-mark-view/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-link-mark-view/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-link/.gitignore b/preact-link/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-link/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-link/README.md b/preact-link/README.md deleted file mode 100644 index 50d7abd9b4..0000000000 --- a/preact-link/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-link - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-link) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-link) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-link preact-link -cd preact-link -npm install -npm run dev -``` diff --git a/preact-link/index.html b/preact-link/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-link/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-link/package.json b/preact-link/package.json deleted file mode 100644 index 4689422411..0000000000 --- a/preact-link/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-link", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-link/src/App.tsx b/preact-link/src/App.tsx deleted file mode 100644 index 1cf0f24636..0000000000 --- a/preact-link/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/link' - -export default function App() { - return -} diff --git a/preact-link/src/app.css b/preact-link/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-link/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-link/src/components/editor/examples/link/editor.tsx b/preact-link/src/components/editor/examples/link/editor.tsx deleted file mode 100644 index d8c42d14ee..0000000000 --- a/preact-link/src/components/editor/examples/link/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-link' -import { InlineMenu } from '../../ui/inline-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/preact-link/src/components/editor/examples/link/extension.ts b/preact-link/src/components/editor/examples/link/extension.ts deleted file mode 100644 index bf499147da..0000000000 --- a/preact-link/src/components/editor/examples/link/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLink } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-link/src/components/editor/examples/link/index.ts b/preact-link/src/components/editor/examples/link/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-link/src/components/editor/examples/link/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-link/src/components/editor/sample/sample-doc-link.ts b/preact-link/src/components/editor/sample/sample-doc-link.ts deleted file mode 100644 index 726cf334fd..0000000000 --- a/preact-link/src/components/editor/sample/sample-doc-link.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is an ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/preact-link/src/components/editor/ui/button/button.tsx b/preact-link/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-link/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-link/src/components/editor/ui/button/index.ts b/preact-link/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-link/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-link/src/components/editor/ui/inline-menu/index.ts b/preact-link/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/preact-link/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/preact-link/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-link/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index a014b74f57..0000000000 --- a/preact-link/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -import type { JSX } from 'preact' -import { useState } from 'preact/hooks' -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/preact' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/preact/inline-popover' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - const handleSubmit = ( - event: JSX.TargetedEvent, - ) => { - event.preventDefault() - const href = event.currentTarget.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
- -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/preact-link/src/main.tsx b/preact-link/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-link/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-link/tsconfig.app.json b/preact-link/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-link/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-link/tsconfig.json b/preact-link/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-link/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-link/tsconfig.node.json b/preact-link/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-link/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-link/vite.config.ts b/preact-link/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-link/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-list-custom-checkbox/.gitignore b/preact-list-custom-checkbox/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-list-custom-checkbox/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-list-custom-checkbox/README.md b/preact-list-custom-checkbox/README.md deleted file mode 100644 index bf2504dd3a..0000000000 --- a/preact-list-custom-checkbox/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-list-custom-checkbox - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-list-custom-checkbox) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-list-custom-checkbox) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-list-custom-checkbox preact-list-custom-checkbox -cd preact-list-custom-checkbox -npm install -npm run dev -``` diff --git a/preact-list-custom-checkbox/index.html b/preact-list-custom-checkbox/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-list-custom-checkbox/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-list-custom-checkbox/package.json b/preact-list-custom-checkbox/package.json deleted file mode 100644 index 2020a7c4e6..0000000000 --- a/preact-list-custom-checkbox/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-list-custom-checkbox", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-list-custom-checkbox/src/App.tsx b/preact-list-custom-checkbox/src/App.tsx deleted file mode 100644 index 96b82e9a84..0000000000 --- a/preact-list-custom-checkbox/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/list-custom-checkbox' - -export default function App() { - return -} diff --git a/preact-list-custom-checkbox/src/app.css b/preact-list-custom-checkbox/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-list-custom-checkbox/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css deleted file mode 100644 index ec631b72ad..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css +++ /dev/null @@ -1,75 +0,0 @@ -div[data-custom-list-css-enabled] - .ProseMirror - .prosemirror-flat-list[data-list-kind='task'] { - & > .list-marker label { - box-sizing: border-box; - display: flex; - position: relative; - left: calc(var(--spacing) * -0.5); - align-items: center; - cursor: pointer; - transition: transform 0.15s ease-in-out; - - &:hover { - transform: scale(1.1); - } - - &::after { - position: absolute; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - content: ''; - color: var(--color-white); - opacity: 0; - } - - /* https://api.iconify.design/lucide.css?icons=check */ - &::after { - display: inline-block; - background-color: currentColor; - -webkit-mask-image: var(--svg); - mask-image: var(--svg); - -webkit-mask-repeat: no-repeat; - mask-repeat: no-repeat; - -webkit-mask-size: 100% 100%; - mask-size: 100% 100%; - --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); - } - - & input { - box-sizing: border-box; - appearance: none; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - margin: 0; - border-width: 1px; - border-style: solid; - border-radius: var(--radius-md); - border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); - box-shadow: var(--shadow-sm); - cursor: pointer; - transition: all 0.15s ease-in-out; - - &:hover { - box-shadow: var(--shadow-md); - } - - &:checked { - border-color: var(--color-red-500); - background-color: var(--color-red-500); - } - } - } - - &[data-list-checked] > .list-marker label { - &::after { - opacity: 1; - } - } - - &[data-list-checked] { - color: var(--color-gray-400); - text-decoration: line-through; - text-decoration-color: var(--color-gray-400); - } -} diff --git a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx deleted file mode 100644 index e335ddb880..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import './custom-list.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-list-custom-checkbox' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ - extension, - defaultContent, - }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/preact-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts deleted file mode 100644 index 972611aed1..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', - }, - { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, - { type: 'text', text: ' for the styles.' }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Completed Task' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Incomplete Task' }], - }, - ], - }, - ], -} diff --git a/preact-list-custom-checkbox/src/components/editor/ui/button/button.tsx b/preact-list-custom-checkbox/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-list-custom-checkbox/src/components/editor/ui/button/index.ts b/preact-list-custom-checkbox/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/preact-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx b/preact-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-list-custom-checkbox/src/main.tsx b/preact-list-custom-checkbox/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-list-custom-checkbox/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-list-custom-checkbox/tsconfig.app.json b/preact-list-custom-checkbox/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-list-custom-checkbox/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-list-custom-checkbox/tsconfig.json b/preact-list-custom-checkbox/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-list-custom-checkbox/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-list-custom-checkbox/tsconfig.node.json b/preact-list-custom-checkbox/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-list-custom-checkbox/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-list-custom-checkbox/vite.config.ts b/preact-list-custom-checkbox/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-list-custom-checkbox/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-list/.gitignore b/preact-list/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-list/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-list/README.md b/preact-list/README.md deleted file mode 100644 index 0817d662fe..0000000000 --- a/preact-list/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-list - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-list) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-list) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-list preact-list -cd preact-list -npm install -npm run dev -``` diff --git a/preact-list/index.html b/preact-list/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-list/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-list/package.json b/preact-list/package.json deleted file mode 100644 index 4395490a90..0000000000 --- a/preact-list/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-list", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-list/src/App.tsx b/preact-list/src/App.tsx deleted file mode 100644 index 73f050ef0c..0000000000 --- a/preact-list/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/list' - -export default function App() { - return -} diff --git a/preact-list/src/app.css b/preact-list/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-list/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-list/src/components/editor/examples/list/editor.tsx b/preact-list/src/components/editor/examples/list/editor.tsx deleted file mode 100644 index f2c6b62a0b..0000000000 --- a/preact-list/src/components/editor/examples/list/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-list' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-list/src/components/editor/examples/list/extension.ts b/preact-list/src/components/editor/examples/list/extension.ts deleted file mode 100644 index f66bae6ff7..0000000000 --- a/preact-list/src/components/editor/examples/list/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineList } from 'prosekit/extensions/list' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineList(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-list/src/components/editor/examples/list/index.ts b/preact-list/src/components/editor/examples/list/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-list/src/components/editor/examples/list/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-list/src/components/editor/sample/sample-doc-list.ts b/preact-list/src/components/editor/sample/sample-doc-list.ts deleted file mode 100644 index 091bc37185..0000000000 --- a/preact-list/src/components/editor/sample/sample-doc-list.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Ordered List' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'toggle', collapsed: true }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, - { - type: 'list', - attrs: { - kind: 'bullet', - }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, - ], - }, - ], - }, - ], -} diff --git a/preact-list/src/components/editor/ui/button/button.tsx b/preact-list/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-list/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-list/src/components/editor/ui/button/index.ts b/preact-list/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-list/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-list/src/components/editor/ui/image-upload-popover/index.ts b/preact-list/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-list/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-list/src/components/editor/ui/toolbar/index.ts b/preact-list/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-list/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-list/src/components/editor/ui/toolbar/toolbar.tsx b/preact-list/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-list/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-list/src/main.tsx b/preact-list/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-list/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-list/tsconfig.app.json b/preact-list/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-list/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-list/tsconfig.json b/preact-list/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-list/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-list/tsconfig.node.json b/preact-list/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-list/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-list/vite.config.ts b/preact-list/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-list/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-loro/.gitignore b/preact-loro/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-loro/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-loro/README.md b/preact-loro/README.md deleted file mode 100644 index f6e9353595..0000000000 --- a/preact-loro/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-loro - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-loro) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-loro) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-loro preact-loro -cd preact-loro -npm install -npm run dev -``` diff --git a/preact-loro/index.html b/preact-loro/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-loro/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-loro/package.json b/preact-loro/package.json deleted file mode 100644 index b472ff7d75..0000000000 --- a/preact-loro/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-preact-loro", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "loro-crdt": "^1.12.1", - "loro-prosemirror": "^0.4.3", - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-wasm": "^3.6.0" - } -} diff --git a/preact-loro/src/App.tsx b/preact-loro/src/App.tsx deleted file mode 100644 index 71d2a6b080..0000000000 --- a/preact-loro/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/loro' - -export default function App() { - return -} diff --git a/preact-loro/src/app.css b/preact-loro/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-loro/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-loro/src/components/editor/examples/loro/editor-component.tsx b/preact-loro/src/components/editor/examples/loro/editor-component.tsx deleted file mode 100644 index 6a46fc6c63..0000000000 --- a/preact-loro/src/components/editor/examples/loro/editor-component.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/loro/style.css' - -import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function EditorComponent(props: { - loro: LoroDocType - awareness: CursorAwareness -}) { - const editor = useMemo(() => { - const extension = defineExtension(props.loro, props.awareness) - return createEditor({ extension }) - }, [props.loro, props.awareness]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-loro/src/components/editor/examples/loro/editor.tsx b/preact-loro/src/components/editor/examples/loro/editor.tsx deleted file mode 100644 index 909b879634..0000000000 --- a/preact-loro/src/components/editor/examples/loro/editor.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { LoroDoc, type AwarenessListener } from 'loro-crdt' -import { CursorAwareness, type LoroDocType } from 'loro-prosemirror' -import { useEffect, useState } from 'preact/hooks' - -import EditorComponent from './editor-component' - -export default function Page() { - const { loroA, awarenessA, loroB, awarenessB } = useLoroDocs() - - return ( -
- - -
- ) -} - -function useLoroDocs() { - const [loroState] = useState(() => { - const loroA: LoroDocType = new LoroDoc() - const loroB: LoroDocType = new LoroDoc() - - const idA = loroA.peerIdStr - const idB = loroB.peerIdStr - - const awarenessA = new CursorAwareness(idA) - const awarenessB = new CursorAwareness(idB) - - return { loroA, loroB, idA, idB, awarenessA, awarenessB } - }) - - useEffect(() => { - const { loroA, loroB, idA, idB, awarenessA, awarenessB } = loroState - loroA.import(loroB.export({ mode: 'update' })) - loroB.import(loroA.export({ mode: 'update' })) - const unsubscribeA = loroA.subscribeLocalUpdates((updates) => { - loroB.import(updates) - }) - const unsubscribeB = loroB.subscribeLocalUpdates((updates) => { - loroA.import(updates) - }) - const awarenessAListener: AwarenessListener = (_, origin) => { - if (origin === 'local') { - awarenessB.apply(awarenessA.encode([idA])) - } - } - const awarenessBListener: AwarenessListener = (_, origin) => { - if (origin === 'local') { - awarenessA.apply(awarenessB.encode([idB])) - } - } - awarenessA.addListener(awarenessAListener) - awarenessB.addListener(awarenessBListener) - return () => { - awarenessA.removeListener(awarenessAListener) - awarenessB.removeListener(awarenessBListener) - unsubscribeA() - unsubscribeB() - } - }, [loroState]) - - return loroState -} diff --git a/preact-loro/src/components/editor/examples/loro/extension.ts b/preact-loro/src/components/editor/examples/loro/extension.ts deleted file mode 100644 index 5a85c5e168..0000000000 --- a/preact-loro/src/components/editor/examples/loro/extension.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineLoro } from 'prosekit/extensions/loro' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { - return union([ - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineLoro({ doc, awareness }), - ]) -} - -export type EditorExtension = ReturnType diff --git a/preact-loro/src/components/editor/examples/loro/index.ts b/preact-loro/src/components/editor/examples/loro/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-loro/src/components/editor/examples/loro/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-loro/src/components/editor/ui/button/button.tsx b/preact-loro/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-loro/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-loro/src/components/editor/ui/button/index.ts b/preact-loro/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-loro/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-loro/src/components/editor/ui/image-upload-popover/index.ts b/preact-loro/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-loro/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-loro/src/components/editor/ui/toolbar/index.ts b/preact-loro/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-loro/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-loro/src/components/editor/ui/toolbar/toolbar.tsx b/preact-loro/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-loro/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-loro/src/main.tsx b/preact-loro/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-loro/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-loro/tsconfig.app.json b/preact-loro/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-loro/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-loro/tsconfig.json b/preact-loro/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-loro/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-loro/tsconfig.node.json b/preact-loro/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-loro/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-loro/vite.config.ts b/preact-loro/vite.config.ts deleted file mode 100644 index f0eb068ec3..0000000000 --- a/preact-loro/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import wasm from 'vite-plugin-wasm' -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [wasm(), preact(), tailwindcss()], -}) diff --git a/preact-mark-rule/.gitignore b/preact-mark-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-mark-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-mark-rule/README.md b/preact-mark-rule/README.md deleted file mode 100644 index 57ef73b293..0000000000 --- a/preact-mark-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-mark-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-mark-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-mark-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-mark-rule preact-mark-rule -cd preact-mark-rule -npm install -npm run dev -``` diff --git a/preact-mark-rule/index.html b/preact-mark-rule/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-mark-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-mark-rule/package.json b/preact-mark-rule/package.json deleted file mode 100644 index 303b34f6da..0000000000 --- a/preact-mark-rule/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-mark-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-mark-rule/src/App.tsx b/preact-mark-rule/src/App.tsx deleted file mode 100644 index 4e93a4bf60..0000000000 --- a/preact-mark-rule/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/mark-rule' - -export default function App() { - return -} diff --git a/preact-mark-rule/src/app.css b/preact-mark-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-mark-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-mark-rule/src/components/editor/examples/mark-rule/editor.tsx b/preact-mark-rule/src/components/editor/examples/mark-rule/editor.tsx deleted file mode 100644 index 3b01b9885a..0000000000 --- a/preact-mark-rule/src/components/editor/examples/mark-rule/editor.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/preact-mark-rule/src/components/editor/examples/mark-rule/extension.ts deleted file mode 100644 index 4a1de40783..0000000000 --- a/preact-mark-rule/src/components/editor/examples/mark-rule/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - defineBaseCommands, - defineBaseKeymap, - defineHistory, - union, -} from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { definePlaceholder } from 'prosekit/extensions/placeholder' -import { defineText } from 'prosekit/extensions/text' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -import { defineIssueLink } from './issue-link' - -export function defineExtension() { - return union( - defineDoc(), - defineText(), - defineParagraph(), - defineHistory(), - defineBaseKeymap(), - defineBaseCommands(), - defineVirtualSelection(), - defineLinkSpec(), - defineLinkMarkRule(), - definePlaceholder({ placeholder: 'Try typing #123' }), - defineIssueLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-mark-rule/src/components/editor/examples/mark-rule/index.ts b/preact-mark-rule/src/components/editor/examples/mark-rule/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-mark-rule/src/components/editor/examples/mark-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/preact-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts deleted file mode 100644 index 3840b5e53d..0000000000 --- a/preact-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { defineMarkSpec, union } from 'prosekit/core' -import { defineMarkRule } from 'prosekit/extensions/mark-rule' - -export function defineIssueLink() { - return union( - defineMarkSpec({ - name: 'issueLink', - inclusive: false, - attrs: { - issueNumber: {}, - }, - toDOM(node) { - const issueNumber = node.attrs.issueNumber as number - return [ - 'a', - { - href: `https://example.com/issues/${issueNumber}`, - title: `Issue #${issueNumber}`, - }, - 0, - ] - }, - }), - defineMarkRule({ - regex: /#(\d+)/g, - type: 'issueLink', - attrs: (match) => { - return { issueNumber: Number.parseInt(match[1] || '0') } - }, - }), - ) -} diff --git a/preact-mark-rule/src/main.tsx b/preact-mark-rule/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-mark-rule/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-mark-rule/tsconfig.app.json b/preact-mark-rule/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-mark-rule/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-mark-rule/tsconfig.json b/preact-mark-rule/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-mark-rule/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-mark-rule/tsconfig.node.json b/preact-mark-rule/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-mark-rule/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-mark-rule/vite.config.ts b/preact-mark-rule/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-mark-rule/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-minimal/.gitignore b/preact-minimal/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-minimal/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-minimal/README.md b/preact-minimal/README.md deleted file mode 100644 index b3c9f5ee76..0000000000 --- a/preact-minimal/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-minimal - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-minimal) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-minimal) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-minimal preact-minimal -cd preact-minimal -npm install -npm run dev -``` diff --git a/preact-minimal/index.html b/preact-minimal/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-minimal/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-minimal/package.json b/preact-minimal/package.json deleted file mode 100644 index 9824d8929e..0000000000 --- a/preact-minimal/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-minimal", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-minimal/src/App.tsx b/preact-minimal/src/App.tsx deleted file mode 100644 index 523aea224a..0000000000 --- a/preact-minimal/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/minimal' - -export default function App() { - return -} diff --git a/preact-minimal/src/app.css b/preact-minimal/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-minimal/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-minimal/src/components/editor/examples/minimal/editor.tsx b/preact-minimal/src/components/editor/examples/minimal/editor.tsx deleted file mode 100644 index 97bf117796..0000000000 --- a/preact-minimal/src/components/editor/examples/minimal/editor.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
- ) -} diff --git a/preact-minimal/src/components/editor/examples/minimal/index.ts b/preact-minimal/src/components/editor/examples/minimal/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-minimal/src/components/editor/examples/minimal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-minimal/src/main.tsx b/preact-minimal/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-minimal/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-minimal/tsconfig.app.json b/preact-minimal/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-minimal/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-minimal/tsconfig.json b/preact-minimal/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-minimal/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-minimal/tsconfig.node.json b/preact-minimal/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-minimal/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-minimal/vite.config.ts b/preact-minimal/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-minimal/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-placeholder/.gitignore b/preact-placeholder/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-placeholder/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-placeholder/README.md b/preact-placeholder/README.md deleted file mode 100644 index 716771bab8..0000000000 --- a/preact-placeholder/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-placeholder - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-placeholder) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-placeholder) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-placeholder preact-placeholder -cd preact-placeholder -npm install -npm run dev -``` diff --git a/preact-placeholder/index.html b/preact-placeholder/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-placeholder/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-placeholder/package.json b/preact-placeholder/package.json deleted file mode 100644 index 92816586f5..0000000000 --- a/preact-placeholder/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-placeholder", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-placeholder/src/App.tsx b/preact-placeholder/src/App.tsx deleted file mode 100644 index 919da8503a..0000000000 --- a/preact-placeholder/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/placeholder' - -export default function App() { - return -} diff --git a/preact-placeholder/src/app.css b/preact-placeholder/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-placeholder/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-placeholder/src/components/editor/examples/placeholder/editor.tsx b/preact-placeholder/src/components/editor/examples/placeholder/editor.tsx deleted file mode 100644 index 28bd4bf9e9..0000000000 --- a/preact-placeholder/src/components/editor/examples/placeholder/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useCallback, useMemo } from 'preact/hooks' -import { createEditor, jsonFromNode, type NodeJSON } from 'prosekit/core' -import type { ProseMirrorNode } from 'prosekit/pm/model' -import { ProseKit, useDocChange } from 'prosekit/preact' - -import { defineExtension } from './extension' - -export default function Editor(props: { - initialContent?: NodeJSON - onDocUpdate?: (doc: NodeJSON) => void -}) { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent: props.initialContent }) - }, [props.initialContent]) - - const { onDocUpdate } = props - const handleDocChange = useCallback( - (doc: ProseMirrorNode) => onDocUpdate?.(jsonFromNode(doc)), - [onDocUpdate], - ) - useDocChange(handleDocChange, { editor }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-placeholder/src/components/editor/examples/placeholder/extension.ts b/preact-placeholder/src/components/editor/examples/placeholder/extension.ts deleted file mode 100644 index 12d0ba26f4..0000000000 --- a/preact-placeholder/src/components/editor/examples/placeholder/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Type something...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-placeholder/src/components/editor/examples/placeholder/index.ts b/preact-placeholder/src/components/editor/examples/placeholder/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-placeholder/src/components/editor/examples/placeholder/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-placeholder/src/main.tsx b/preact-placeholder/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-placeholder/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-placeholder/tsconfig.app.json b/preact-placeholder/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-placeholder/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-placeholder/tsconfig.json b/preact-placeholder/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-placeholder/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-placeholder/tsconfig.node.json b/preact-placeholder/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-placeholder/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-placeholder/vite.config.ts b/preact-placeholder/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-placeholder/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-readonly/.gitignore b/preact-readonly/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-readonly/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-readonly/README.md b/preact-readonly/README.md deleted file mode 100644 index ad30c0b214..0000000000 --- a/preact-readonly/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-readonly - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-readonly) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-readonly) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-readonly preact-readonly -cd preact-readonly -npm install -npm run dev -``` diff --git a/preact-readonly/index.html b/preact-readonly/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-readonly/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-readonly/package.json b/preact-readonly/package.json deleted file mode 100644 index d556c61138..0000000000 --- a/preact-readonly/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-readonly", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-readonly/src/App.tsx b/preact-readonly/src/App.tsx deleted file mode 100644 index dc728e840f..0000000000 --- a/preact-readonly/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/readonly' - -export default function App() { - return -} diff --git a/preact-readonly/src/app.css b/preact-readonly/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-readonly/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-readonly/src/components/editor/examples/readonly/editor.tsx b/preact-readonly/src/components/editor/examples/readonly/editor.tsx deleted file mode 100644 index 0554371f6f..0000000000 --- a/preact-readonly/src/components/editor/examples/readonly/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-readonly' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-readonly/src/components/editor/examples/readonly/extension.ts b/preact-readonly/src/components/editor/examples/readonly/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/preact-readonly/src/components/editor/examples/readonly/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/preact-readonly/src/components/editor/examples/readonly/index.ts b/preact-readonly/src/components/editor/examples/readonly/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-readonly/src/components/editor/examples/readonly/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-readonly/src/components/editor/examples/readonly/toolbar.tsx b/preact-readonly/src/components/editor/examples/readonly/toolbar.tsx deleted file mode 100644 index 9ba96d3459..0000000000 --- a/preact-readonly/src/components/editor/examples/readonly/toolbar.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { Button } from '../../ui/button' - -import { useReadonly } from './use-readonly' - -export default function Toolbar() { - const { readonly, setReadonly } = useReadonly() - - return ( -
- - - -
- ) -} diff --git a/preact-readonly/src/components/editor/examples/readonly/use-readonly.ts b/preact-readonly/src/components/editor/examples/readonly/use-readonly.ts deleted file mode 100644 index 1b8ba24ebe..0000000000 --- a/preact-readonly/src/components/editor/examples/readonly/use-readonly.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { useMemo, useState } from 'preact/hooks' -import { defineReadonly } from 'prosekit/extensions/readonly' -import { useExtension } from 'prosekit/preact' - -export function useReadonly() { - const [readonly, setReadonly] = useState(true) - - const extension = useMemo(() => { - return readonly ? defineReadonly() : null - }, [readonly]) - useExtension(extension) - - return { readonly, setReadonly } -} diff --git a/preact-readonly/src/components/editor/sample/sample-doc-readonly.ts b/preact-readonly/src/components/editor/sample/sample-doc-readonly.ts deleted file mode 100644 index abd9e2c6ac..0000000000 --- a/preact-readonly/src/components/editor/sample/sample-doc-readonly.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', - }, - ], - }, - ], -} diff --git a/preact-readonly/src/components/editor/ui/button/button.tsx b/preact-readonly/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-readonly/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-readonly/src/components/editor/ui/button/index.ts b/preact-readonly/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-readonly/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-readonly/src/main.tsx b/preact-readonly/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-readonly/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-readonly/tsconfig.app.json b/preact-readonly/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-readonly/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-readonly/tsconfig.json b/preact-readonly/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-readonly/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-readonly/tsconfig.node.json b/preact-readonly/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-readonly/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-readonly/vite.config.ts b/preact-readonly/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-readonly/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-rtl/.gitignore b/preact-rtl/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-rtl/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-rtl/README.md b/preact-rtl/README.md deleted file mode 100644 index 6bdae8c7f1..0000000000 --- a/preact-rtl/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-rtl - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-rtl) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-rtl) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-rtl preact-rtl -cd preact-rtl -npm install -npm run dev -``` diff --git a/preact-rtl/index.html b/preact-rtl/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-rtl/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-rtl/package.json b/preact-rtl/package.json deleted file mode 100644 index 9e187a1313..0000000000 --- a/preact-rtl/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-rtl", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-rtl/src/App.tsx b/preact-rtl/src/App.tsx deleted file mode 100644 index b7c8653ece..0000000000 --- a/preact-rtl/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/rtl' - -export default function App() { - return -} diff --git a/preact-rtl/src/app.css b/preact-rtl/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-rtl/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-rtl/src/components/editor/examples/rtl/editor.tsx b/preact-rtl/src/components/editor/examples/rtl/editor.tsx deleted file mode 100644 index 7ceb17d06b..0000000000 --- a/preact-rtl/src/components/editor/examples/rtl/editor.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-rtl' -import { sampleUploader } from '../../sample/sample-uploader' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' -import { InlineMenu } from '../../ui/inline-menu' -import { SlashMenu } from '../../ui/slash-menu' -import { TableHandle } from '../../ui/table-handle' -import { Toolbar } from '../../ui/toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
- - - - - -
-
-
- ) -} diff --git a/preact-rtl/src/components/editor/examples/rtl/index.ts b/preact-rtl/src/components/editor/examples/rtl/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-rtl/src/components/editor/examples/rtl/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-rtl/src/components/editor/sample/sample-doc-rtl.ts b/preact-rtl/src/components/editor/sample/sample-doc-rtl.ts deleted file mode 100644 index 696e797724..0000000000 --- a/preact-rtl/src/components/editor/sample/sample-doc-rtl.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const translation = { - Paragraph: 'فقرة', - 'Root list item': 'عنصر قائمة جذري', - 'Sub list item': 'عنصر قائمة فرعي', - 'Completed task': 'مهمة مكتملة', - 'Pending task': 'مهمة قيد الانتظار', - Quote: 'اقتباس', -} as const - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Right to Left' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Paragraph'] }], - }, - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Root list item'] }], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Completed task'] }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Pending task'] }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: 'hello world', - }, - ], - }, - - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, - ], - }, - ], - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: translation['Quote'], - }, - ], - }, - ], - }, - ], -} diff --git a/preact-rtl/src/components/editor/sample/sample-uploader.ts b/preact-rtl/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/preact-rtl/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/preact-rtl/src/components/editor/ui/block-handle/block-handle.tsx b/preact-rtl/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 8f5fe62e40..0000000000 --- a/preact-rtl/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/preact/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/preact-rtl/src/components/editor/ui/block-handle/index.ts b/preact-rtl/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/preact-rtl/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/preact-rtl/src/components/editor/ui/button/button.tsx b/preact-rtl/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-rtl/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-rtl/src/components/editor/ui/button/index.ts b/preact-rtl/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-rtl/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/preact-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx deleted file mode 100644 index 6ace546a12..0000000000 --- a/preact-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { DropIndicator as BaseDropIndicator } from 'prosekit/preact/drop-indicator' - -export default function DropIndicator() { - return -} diff --git a/preact-rtl/src/components/editor/ui/drop-indicator/index.ts b/preact-rtl/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index f8fb7139c4..0000000000 --- a/preact-rtl/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator' diff --git a/preact-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-rtl/src/components/editor/ui/image-upload-popover/index.ts b/preact-rtl/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-rtl/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-rtl/src/components/editor/ui/inline-menu/index.ts b/preact-rtl/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/preact-rtl/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/preact-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index a014b74f57..0000000000 --- a/preact-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -import type { JSX } from 'preact' -import { useState } from 'preact/hooks' -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/preact' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/preact/inline-popover' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - const handleSubmit = ( - event: JSX.TargetedEvent, - ) => { - event.preventDefault() - const href = event.currentTarget.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
- -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/preact-rtl/src/components/editor/ui/slash-menu/index.ts b/preact-rtl/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/preact-rtl/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index bedf7d7ebb..0000000000 --- a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { AutocompleteEmpty } from 'prosekit/preact/autocomplete' - -export default function SlashMenuEmpty() { - return ( - - No results - - ) -} diff --git a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 1bb81f797d..0000000000 --- a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { AutocompleteItem } from 'prosekit/preact/autocomplete' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}) { - return ( - - {props.label} - {props.kbd && ( - - {props.kbd} - - )} - - ) -} diff --git a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index 092327c28e..0000000000 --- a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/preact' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/preact/autocomplete' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor.commands.setParagraph()} - /> - - editor.commands.setHeading({ level: 1 })} - /> - - editor.commands.setHeading({ level: 2 })} - /> - - editor.commands.setHeading({ level: 3 })} - /> - - editor.commands.wrapInList({ kind: 'bullet' })} - /> - - editor.commands.wrapInList({ kind: 'ordered' })} - /> - - editor.commands.wrapInList({ kind: 'task' })} - /> - - editor.commands.wrapInList({ kind: 'toggle' })} - /> - - editor.commands.setBlockquote()} - /> - - editor.commands.insertTable({ row: 3, col: 3 })} - /> - - editor.commands.insertHorizontalRule()} - /> - - editor.commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/preact-rtl/src/components/editor/ui/table-handle/index.ts b/preact-rtl/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/preact-rtl/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/preact-rtl/src/components/editor/ui/table-handle/table-handle.tsx b/preact-rtl/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index 6182b185c6..0000000000 --- a/preact-rtl/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/preact' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/preact/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/preact/table-handle' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props) { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - {state.addTableColumnBefore.canExec && ( - - Insert Left - - )} - {state.addTableColumnAfter.canExec && ( - - Insert Right - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableColumn.canExec && ( - - Delete Column - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
- - - - -
-
- - - {state.addTableRowAbove.canExec && ( - - Insert Above - - )} - {state.addTableRowBelow.canExec && ( - - Insert Below - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableRow.canExec && ( - - Delete Row - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
-
- ) -} diff --git a/preact-rtl/src/components/editor/ui/toolbar/index.ts b/preact-rtl/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-rtl/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-rtl/src/components/editor/ui/toolbar/toolbar.tsx b/preact-rtl/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-rtl/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-rtl/src/main.tsx b/preact-rtl/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-rtl/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-rtl/tsconfig.app.json b/preact-rtl/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-rtl/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-rtl/tsconfig.json b/preact-rtl/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-rtl/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-rtl/tsconfig.node.json b/preact-rtl/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-rtl/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-rtl/vite.config.ts b/preact-rtl/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-rtl/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-save-html/.gitignore b/preact-save-html/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-save-html/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-save-html/README.md b/preact-save-html/README.md deleted file mode 100644 index 329319f3aa..0000000000 --- a/preact-save-html/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-save-html - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-save-html) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-save-html) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-save-html preact-save-html -cd preact-save-html -npm install -npm run dev -``` diff --git a/preact-save-html/index.html b/preact-save-html/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-save-html/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-save-html/package.json b/preact-save-html/package.json deleted file mode 100644 index 3aff0753f4..0000000000 --- a/preact-save-html/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-save-html", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-save-html/src/App.tsx b/preact-save-html/src/App.tsx deleted file mode 100644 index cd1a678bb6..0000000000 --- a/preact-save-html/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-html' - -export default function App() { - return -} diff --git a/preact-save-html/src/app.css b/preact-save-html/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-save-html/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-save-html/src/components/editor/examples/save-html/editor.tsx b/preact-save-html/src/components/editor/examples/save-html/editor.tsx deleted file mode 100644 index 94b40c24e8..0000000000 --- a/preact-save-html/src/components/editor/examples/save-html/editor.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useCallback, useMemo, useState } from 'preact/hooks' -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, jsonFromHTML } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/preact' - -export default function Editor() { - // A list of saved documents, stored as HTML strings - const [records, setRecords] = useState([]) - // Whether there are unsaved changes - const [hasUnsavedChange, setHasUnsavedChange] = useState(false) - // A key to force a re-render of the editor - const [key, setKey] = useState(1) - - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension }) - }, []) - - const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) - useDocChange(handleDocChange, { editor }) - - const handleSave = useCallback(() => { - const record = editor.getDocHTML() - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - }, [editor]) - - const handleLoad = useCallback( - (record: string) => { - editor.setContent(jsonFromHTML(record, { schema: editor.schema })) - setHasUnsavedChange(false) - setKey((prev) => prev + 1) - }, - [editor], - ) - - return ( -
- -
    - {records.map((record, index) => ( -
  • - - -
    {record}
    -
    -
  • - ))} -
- -
-
-
-
-
- ) -} diff --git a/preact-save-html/src/components/editor/examples/save-html/index.ts b/preact-save-html/src/components/editor/examples/save-html/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-save-html/src/components/editor/examples/save-html/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-save-html/src/main.tsx b/preact-save-html/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-save-html/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-save-html/tsconfig.app.json b/preact-save-html/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-save-html/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-save-html/tsconfig.json b/preact-save-html/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-save-html/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-save-html/tsconfig.node.json b/preact-save-html/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-save-html/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-save-html/vite.config.ts b/preact-save-html/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-save-html/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-save-json/.gitignore b/preact-save-json/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-save-json/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-save-json/README.md b/preact-save-json/README.md deleted file mode 100644 index b3d34b02e3..0000000000 --- a/preact-save-json/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-save-json - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-save-json) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-save-json) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-save-json preact-save-json -cd preact-save-json -npm install -npm run dev -``` diff --git a/preact-save-json/index.html b/preact-save-json/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-save-json/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-save-json/package.json b/preact-save-json/package.json deleted file mode 100644 index 9ed2eb08a3..0000000000 --- a/preact-save-json/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-save-json", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-save-json/src/App.tsx b/preact-save-json/src/App.tsx deleted file mode 100644 index c35583f0b4..0000000000 --- a/preact-save-json/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-json' - -export default function App() { - return -} diff --git a/preact-save-json/src/app.css b/preact-save-json/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-save-json/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-save-json/src/components/editor/examples/save-json/editor.tsx b/preact-save-json/src/components/editor/examples/save-json/editor.tsx deleted file mode 100644 index c6028ac7a4..0000000000 --- a/preact-save-json/src/components/editor/examples/save-json/editor.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useCallback, useMemo, useState } from 'preact/hooks' -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/preact' - -export default function Editor() { - // A list of saved documents, stored as JSON strings - const [records, setRecords] = useState([]) - // Whether there are unsaved changes - const [hasUnsavedChange, setHasUnsavedChange] = useState(false) - // A key to force a re-render of the editor - const [key, setKey] = useState(1) - - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension }) - }, []) - - const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) - useDocChange(handleDocChange, { editor }) - - const handleSave = useCallback(() => { - const record = JSON.stringify(editor.getDocJSON()) - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - }, [editor]) - - const handleLoad = useCallback( - (record: string) => { - editor.setContent(JSON.parse(record) as NodeJSON) - setHasUnsavedChange(false) - setKey((prev) => prev + 1) - }, - [editor], - ) - - return ( -
- -
    - {records.map((record, index) => ( -
  • - - -
    {record}
    -
    -
  • - ))} -
- -
-
-
-
-
- ) -} diff --git a/preact-save-json/src/components/editor/examples/save-json/index.ts b/preact-save-json/src/components/editor/examples/save-json/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-save-json/src/components/editor/examples/save-json/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-save-json/src/main.tsx b/preact-save-json/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-save-json/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-save-json/tsconfig.app.json b/preact-save-json/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-save-json/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-save-json/tsconfig.json b/preact-save-json/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-save-json/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-save-json/tsconfig.node.json b/preact-save-json/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-save-json/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-save-json/vite.config.ts b/preact-save-json/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-save-json/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-save-markdown/.gitignore b/preact-save-markdown/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-save-markdown/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-save-markdown/README.md b/preact-save-markdown/README.md deleted file mode 100644 index d5c4ab6272..0000000000 --- a/preact-save-markdown/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-save-markdown - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-save-markdown) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-save-markdown) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-save-markdown preact-save-markdown -cd preact-save-markdown -npm install -npm run dev -``` diff --git a/preact-save-markdown/index.html b/preact-save-markdown/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-save-markdown/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-save-markdown/package.json b/preact-save-markdown/package.json deleted file mode 100644 index 3f31b27efc..0000000000 --- a/preact-save-markdown/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "example-preact-save-markdown", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0", - "rehype-parse": "^9.0.1", - "rehype-remark": "^10.0.1", - "remark-gfm": "^4.0.1", - "remark-html": "^16.0.1", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.5" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-save-markdown/src/App.tsx b/preact-save-markdown/src/App.tsx deleted file mode 100644 index 776d1fdf5b..0000000000 --- a/preact-save-markdown/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-markdown' - -export default function App() { - return -} diff --git a/preact-save-markdown/src/app.css b/preact-save-markdown/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-save-markdown/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-save-markdown/src/components/editor/examples/save-markdown/editor.tsx b/preact-save-markdown/src/components/editor/examples/save-markdown/editor.tsx deleted file mode 100644 index 06a52923f5..0000000000 --- a/preact-save-markdown/src/components/editor/examples/save-markdown/editor.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useCallback, useMemo, useState } from 'preact/hooks' -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, jsonFromHTML } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/preact' - -import { htmlFromMarkdown, markdownFromHTML } from './markdown' - -export default function Editor() { - // A list of saved documents, stored as Markdown strings - const [records, setRecords] = useState([]) - // Whether there are unsaved changes - const [hasUnsavedChange, setHasUnsavedChange] = useState(false) - // A key to force a re-render of the editor - const [key, setKey] = useState(1) - - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension }) - }, []) - - const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) - useDocChange(handleDocChange, { editor }) - - const handleSave = useCallback(() => { - const html = editor.getDocHTML() - const record = markdownFromHTML(html) - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - }, [editor]) - - const handleLoad = useCallback( - (record: string) => { - const html = htmlFromMarkdown(record) - editor.setContent(jsonFromHTML(html, { schema: editor.schema })) - setHasUnsavedChange(false) - setKey((prev) => prev + 1) - }, - [editor], - ) - - return ( -
- -
    - {records.map((record, index) => ( -
  • - - -
    {record}
    -
    -
  • - ))} -
- -
-
-
-
-
- ) -} diff --git a/preact-save-markdown/src/components/editor/examples/save-markdown/index.ts b/preact-save-markdown/src/components/editor/examples/save-markdown/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-save-markdown/src/components/editor/examples/save-markdown/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/preact-save-markdown/src/components/editor/examples/save-markdown/markdown.ts deleted file mode 100644 index 3f930adad2..0000000000 --- a/preact-save-markdown/src/components/editor/examples/save-markdown/markdown.ts +++ /dev/null @@ -1,26 +0,0 @@ -import rehypeParse from 'rehype-parse' -import rehypeRemark from 'rehype-remark' -import remarkGfm from 'remark-gfm' -import remarkHtml from 'remark-html' -import remarkParse from 'remark-parse' -import remarkStringify from 'remark-stringify' -import { unified } from 'unified' - -export function markdownFromHTML(html: string): string { - return unified() - .use(rehypeParse) - .use(rehypeRemark) - .use(remarkGfm) - .use(remarkStringify) - .processSync(html) - .toString() -} - -export function htmlFromMarkdown(markdown: string): string { - return unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkHtml) - .processSync(markdown) - .toString() -} diff --git a/preact-save-markdown/src/main.tsx b/preact-save-markdown/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-save-markdown/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-save-markdown/tsconfig.app.json b/preact-save-markdown/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-save-markdown/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-save-markdown/tsconfig.json b/preact-save-markdown/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-save-markdown/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-save-markdown/tsconfig.node.json b/preact-save-markdown/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-save-markdown/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-save-markdown/vite.config.ts b/preact-save-markdown/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-save-markdown/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-search/.gitignore b/preact-search/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-search/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-search/README.md b/preact-search/README.md deleted file mode 100644 index b854505b4d..0000000000 --- a/preact-search/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-search - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-search) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-search) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-search preact-search -cd preact-search -npm install -npm run dev -``` diff --git a/preact-search/index.html b/preact-search/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-search/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-search/package.json b/preact-search/package.json deleted file mode 100644 index b797dda6b4..0000000000 --- a/preact-search/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-search", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-search/src/App.tsx b/preact-search/src/App.tsx deleted file mode 100644 index 2f6b77056f..0000000000 --- a/preact-search/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/search' - -export default function App() { - return -} diff --git a/preact-search/src/app.css b/preact-search/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-search/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-search/src/components/editor/examples/search/editor.tsx b/preact-search/src/components/editor/examples/search/editor.tsx deleted file mode 100644 index 29f4e7ce4b..0000000000 --- a/preact-search/src/components/editor/examples/search/editor.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/search/style.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-search' -import { Search } from '../../ui/search' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ - extension, - defaultContent, - }) - }, [defaultContent]) - - return ( - -
-
- -
-
-
-
- ) -} diff --git a/preact-search/src/components/editor/examples/search/extension.ts b/preact-search/src/components/editor/examples/search/extension.ts deleted file mode 100644 index 10ff13f614..0000000000 --- a/preact-search/src/components/editor/examples/search/extension.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineSearchCommands } from 'prosekit/extensions/search' - -export function defineExtension() { - return union(defineBasicExtension(), defineSearchCommands()) -} - -export type EditorExtension = ReturnType diff --git a/preact-search/src/components/editor/examples/search/index.ts b/preact-search/src/components/editor/examples/search/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-search/src/components/editor/examples/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-search/src/components/editor/sample/sample-doc-search.ts b/preact-search/src/components/editor/sample/sample-doc-search.ts deleted file mode 100644 index c8160cca2a..0000000000 --- a/preact-search/src/components/editor/sample/sample-doc-search.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Baa, baa, black sheep,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Have you any wool?', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Yes, sir, yes, sir,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Three bags full;', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'One for the master,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the dame,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the little boy', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Who lives down the lane.', - }, - ], - }, - ], -} diff --git a/preact-search/src/components/editor/ui/button/button.tsx b/preact-search/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-search/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-search/src/components/editor/ui/button/index.ts b/preact-search/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-search/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-search/src/components/editor/ui/search/index.ts b/preact-search/src/components/editor/ui/search/index.ts deleted file mode 100644 index 0a1f03c720..0000000000 --- a/preact-search/src/components/editor/ui/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Search } from './search' diff --git a/preact-search/src/components/editor/ui/search/search.tsx b/preact-search/src/components/editor/ui/search/search.tsx deleted file mode 100644 index e8f88802a9..0000000000 --- a/preact-search/src/components/editor/ui/search/search.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import { useMemo, useState } from 'preact/hooks' -import { - defineSearchQuery, - type SearchCommandsExtension, -} from 'prosekit/extensions/search' -import { useEditor, useExtension } from 'prosekit/preact' - -import { Button } from '../button' - -export default function Search(props: { onClose?: VoidFunction }) { - const [showReplace, setShowReplace] = useState(false) - const toggleReplace = () => setShowReplace((value) => !value) - - const [searchText, setSearchText] = useState('') - const [replaceText, setReplaceText] = useState('') - const [caseSensitive, setCaseSensitive] = useState(false) - const [wholeWord, setWholeWord] = useState(false) - const [regexp, setRegexp] = useState(false) - const [literal, setLiteral] = useState(false) - - const extension = useMemo(() => { - if (!searchText) { - return null - } - return defineSearchQuery({ - search: searchText, - replace: replaceText, - caseSensitive, - wholeWord, - regexp, - literal, - }) - }, [searchText, replaceText, caseSensitive, wholeWord, regexp, literal]) - - useExtension(extension) - - const editor = useEditor() - - const handleSearchKeyDown = (event: KeyboardEvent) => { - if (isEnter(event)) { - event.preventDefault() - editor.commands.findNext() - } else if (isShiftEnter(event)) { - event.preventDefault() - editor.commands.findPrev() - } - } - - const handleReplaceKeyDown = (event: KeyboardEvent) => { - if (isEnter(event)) { - event.preventDefault() - editor.commands.replaceNext() - } else if (isShiftEnter(event)) { - event.preventDefault() - editor.commands.replaceAll() - } - } - - return ( -
- - setSearchText(event.currentTarget.value)} - onKeyDown={handleSearchKeyDown} - className="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" - /> -
- - - - - - - -
- {showReplace && ( - setReplaceText(event.currentTarget.value)} - onKeyDown={handleReplaceKeyDown} - className="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" - /> - )} - {showReplace && ( -
- - -
- )} -
- ) -} - -function isEnter(event: KeyboardEvent) { - return ( - event.key === 'Enter' && - !event.shiftKey && - !event.metaKey && - !event.altKey && - !event.ctrlKey && - !event.isComposing - ) -} - -function isShiftEnter(event: KeyboardEvent) { - return ( - event.key === 'Enter' && - event.shiftKey && - !event.metaKey && - !event.altKey && - !event.ctrlKey && - !event.isComposing - ) -} diff --git a/preact-search/src/main.tsx b/preact-search/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-search/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-search/tsconfig.app.json b/preact-search/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-search/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-search/tsconfig.json b/preact-search/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-search/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-search/tsconfig.node.json b/preact-search/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-search/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-search/vite.config.ts b/preact-search/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-search/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-slash-menu/.gitignore b/preact-slash-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-slash-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-slash-menu/README.md b/preact-slash-menu/README.md deleted file mode 100644 index aecb620e7b..0000000000 --- a/preact-slash-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-slash-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-slash-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-slash-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-slash-menu preact-slash-menu -cd preact-slash-menu -npm install -npm run dev -``` diff --git a/preact-slash-menu/index.html b/preact-slash-menu/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-slash-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-slash-menu/package.json b/preact-slash-menu/package.json deleted file mode 100644 index 2092e82a7c..0000000000 --- a/preact-slash-menu/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-slash-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-slash-menu/src/App.tsx b/preact-slash-menu/src/App.tsx deleted file mode 100644 index cf430661be..0000000000 --- a/preact-slash-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/slash-menu' - -export default function App() { - return -} diff --git a/preact-slash-menu/src/app.css b/preact-slash-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-slash-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-slash-menu/src/components/editor/examples/slash-menu/editor.tsx b/preact-slash-menu/src/components/editor/examples/slash-menu/editor.tsx deleted file mode 100644 index ddfc10b34a..0000000000 --- a/preact-slash-menu/src/components/editor/examples/slash-menu/editor.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { SlashMenu } from '../../ui/slash-menu' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/preact-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/preact-slash-menu/src/components/editor/examples/slash-menu/extension.ts deleted file mode 100644 index 0edda60136..0000000000 --- a/preact-slash-menu/src/components/editor/examples/slash-menu/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-slash-menu/src/components/editor/examples/slash-menu/index.ts b/preact-slash-menu/src/components/editor/examples/slash-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-slash-menu/src/components/editor/examples/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-slash-menu/src/components/editor/ui/slash-menu/index.ts b/preact-slash-menu/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/preact-slash-menu/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index bedf7d7ebb..0000000000 --- a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { AutocompleteEmpty } from 'prosekit/preact/autocomplete' - -export default function SlashMenuEmpty() { - return ( - - No results - - ) -} diff --git a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 1bb81f797d..0000000000 --- a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { AutocompleteItem } from 'prosekit/preact/autocomplete' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}) { - return ( - - {props.label} - {props.kbd && ( - - {props.kbd} - - )} - - ) -} diff --git a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index 092327c28e..0000000000 --- a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/preact' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/preact/autocomplete' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor.commands.setParagraph()} - /> - - editor.commands.setHeading({ level: 1 })} - /> - - editor.commands.setHeading({ level: 2 })} - /> - - editor.commands.setHeading({ level: 3 })} - /> - - editor.commands.wrapInList({ kind: 'bullet' })} - /> - - editor.commands.wrapInList({ kind: 'ordered' })} - /> - - editor.commands.wrapInList({ kind: 'task' })} - /> - - editor.commands.wrapInList({ kind: 'toggle' })} - /> - - editor.commands.setBlockquote()} - /> - - editor.commands.insertTable({ row: 3, col: 3 })} - /> - - editor.commands.insertHorizontalRule()} - /> - - editor.commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/preact-slash-menu/src/main.tsx b/preact-slash-menu/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-slash-menu/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-slash-menu/tsconfig.app.json b/preact-slash-menu/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-slash-menu/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-slash-menu/tsconfig.json b/preact-slash-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-slash-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-slash-menu/tsconfig.node.json b/preact-slash-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-slash-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-slash-menu/vite.config.ts b/preact-slash-menu/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-slash-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-strike/.gitignore b/preact-strike/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-strike/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-strike/README.md b/preact-strike/README.md deleted file mode 100644 index 3ae1aaa017..0000000000 --- a/preact-strike/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-strike - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-strike) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-strike) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-strike preact-strike -cd preact-strike -npm install -npm run dev -``` diff --git a/preact-strike/index.html b/preact-strike/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-strike/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-strike/package.json b/preact-strike/package.json deleted file mode 100644 index c2028d282f..0000000000 --- a/preact-strike/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-strike", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-strike/src/App.tsx b/preact-strike/src/App.tsx deleted file mode 100644 index 497a57c0d8..0000000000 --- a/preact-strike/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/strike' - -export default function App() { - return -} diff --git a/preact-strike/src/app.css b/preact-strike/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-strike/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-strike/src/components/editor/examples/strike/editor.tsx b/preact-strike/src/components/editor/examples/strike/editor.tsx deleted file mode 100644 index f9580e6f44..0000000000 --- a/preact-strike/src/components/editor/examples/strike/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-strike' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-strike/src/components/editor/examples/strike/extension.ts b/preact-strike/src/components/editor/examples/strike/extension.ts deleted file mode 100644 index c013303ccc..0000000000 --- a/preact-strike/src/components/editor/examples/strike/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineStrike(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-strike/src/components/editor/examples/strike/index.ts b/preact-strike/src/components/editor/examples/strike/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-strike/src/components/editor/examples/strike/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-strike/src/components/editor/examples/strike/toolbar.tsx b/preact-strike/src/components/editor/examples/strike/toolbar.tsx deleted file mode 100644 index 3566b6c801..0000000000 --- a/preact-strike/src/components/editor/examples/strike/toolbar.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - strike: { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/preact-strike/src/components/editor/sample/sample-doc-strike.ts b/preact-strike/src/components/editor/sample/sample-doc-strike.ts deleted file mode 100644 index 2e025e9b02..0000000000 --- a/preact-strike/src/components/editor/sample/sample-doc-strike.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'This is strike', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/preact-strike/src/components/editor/ui/button/button.tsx b/preact-strike/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-strike/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-strike/src/components/editor/ui/button/index.ts b/preact-strike/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-strike/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-strike/src/main.tsx b/preact-strike/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-strike/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-strike/tsconfig.app.json b/preact-strike/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-strike/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-strike/tsconfig.json b/preact-strike/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-strike/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-strike/tsconfig.node.json b/preact-strike/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-strike/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-strike/vite.config.ts b/preact-strike/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-strike/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-sub-sup/.gitignore b/preact-sub-sup/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-sub-sup/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-sub-sup/README.md b/preact-sub-sup/README.md deleted file mode 100644 index df69875b3b..0000000000 --- a/preact-sub-sup/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-sub-sup - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-sub-sup) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-sub-sup) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-sub-sup preact-sub-sup -cd preact-sub-sup -npm install -npm run dev -``` diff --git a/preact-sub-sup/index.html b/preact-sub-sup/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-sub-sup/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-sub-sup/package.json b/preact-sub-sup/package.json deleted file mode 100644 index 76fd495fa3..0000000000 --- a/preact-sub-sup/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-sub-sup", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-sub-sup/src/App.tsx b/preact-sub-sup/src/App.tsx deleted file mode 100644 index 48e43d6423..0000000000 --- a/preact-sub-sup/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/sub-sup' - -export default function App() { - return -} diff --git a/preact-sub-sup/src/app.css b/preact-sub-sup/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-sub-sup/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-sub-sup/src/components/editor/examples/sub-sup/editor.tsx b/preact-sub-sup/src/components/editor/examples/sub-sup/editor.tsx deleted file mode 100644 index 6f37abd3c9..0000000000 --- a/preact-sub-sup/src/components/editor/examples/sub-sup/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-sub-sup' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/preact-sub-sup/src/components/editor/examples/sub-sup/extension.ts deleted file mode 100644 index bd67245f86..0000000000 --- a/preact-sub-sup/src/components/editor/examples/sub-sup/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineMarkInputRule } from 'prosekit/extensions/input-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineSubscript } from 'prosekit/extensions/subscript' -import { defineSuperscript } from 'prosekit/extensions/superscript' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineSubscript(), - defineSuperscript(), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ - : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, - type: 'subscript', - }), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ - : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, - type: 'superscript', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-sub-sup/src/components/editor/examples/sub-sup/index.ts b/preact-sub-sup/src/components/editor/examples/sub-sup/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-sub-sup/src/components/editor/examples/sub-sup/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx b/preact-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx deleted file mode 100644 index e62a1556b8..0000000000 --- a/preact-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - subscript: { - isActive: editor.marks.subscript.isActive(), - canExec: editor.commands.toggleSubscript.canExec(), - command: () => editor.commands.toggleSubscript(), - }, - superscript: { - isActive: editor.marks.superscript.isActive(), - canExec: editor.commands.toggleSuperscript.canExec(), - command: () => editor.commands.toggleSuperscript(), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - -
- ) -} diff --git a/preact-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/preact-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts deleted file mode 100644 index 011be750dc..0000000000 --- a/preact-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'H', - }, - { - type: 'text', - marks: [ - { - type: 'subscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: 'O is water. x', - }, - { - type: 'text', - marks: [ - { - type: 'superscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: ' is a square.', - }, - ], - }, - ], -} diff --git a/preact-sub-sup/src/components/editor/ui/button/button.tsx b/preact-sub-sup/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-sub-sup/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-sub-sup/src/components/editor/ui/button/index.ts b/preact-sub-sup/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-sub-sup/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-sub-sup/src/main.tsx b/preact-sub-sup/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-sub-sup/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-sub-sup/tsconfig.app.json b/preact-sub-sup/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-sub-sup/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-sub-sup/tsconfig.json b/preact-sub-sup/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-sub-sup/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-sub-sup/tsconfig.node.json b/preact-sub-sup/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-sub-sup/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-sub-sup/vite.config.ts b/preact-sub-sup/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-sub-sup/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-table/.gitignore b/preact-table/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-table/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-table/README.md b/preact-table/README.md deleted file mode 100644 index bfb4949a6c..0000000000 --- a/preact-table/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-table - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-table) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-table) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-table preact-table -cd preact-table -npm install -npm run dev -``` diff --git a/preact-table/index.html b/preact-table/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-table/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-table/package.json b/preact-table/package.json deleted file mode 100644 index 2d065dacc1..0000000000 --- a/preact-table/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-table", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-table/src/App.tsx b/preact-table/src/App.tsx deleted file mode 100644 index 9d9d957adb..0000000000 --- a/preact-table/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/table' - -export default function App() { - return -} diff --git a/preact-table/src/app.css b/preact-table/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-table/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-table/src/components/editor/examples/table/editor.tsx b/preact-table/src/components/editor/examples/table/editor.tsx deleted file mode 100644 index 91d033b947..0000000000 --- a/preact-table/src/components/editor/examples/table/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-table' -import { TableHandle } from '../../ui/table-handle' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/preact-table/src/components/editor/examples/table/extension.ts b/preact-table/src/components/editor/examples/table/extension.ts deleted file mode 100644 index ee7b142041..0000000000 --- a/preact-table/src/components/editor/examples/table/extension.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineTable(), - defineHistory(), - defineGapCursor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-table/src/components/editor/examples/table/index.ts b/preact-table/src/components/editor/examples/table/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-table/src/components/editor/examples/table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-table/src/components/editor/sample/sample-doc-table.ts b/preact-table/src/components/editor/sample/sample-doc-table.ts deleted file mode 100644 index c737121672..0000000000 --- a/preact-table/src/components/editor/sample/sample-doc-table.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D1', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D2', - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], -} diff --git a/preact-table/src/components/editor/ui/table-handle/index.ts b/preact-table/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/preact-table/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/preact-table/src/components/editor/ui/table-handle/table-handle.tsx b/preact-table/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index 6182b185c6..0000000000 --- a/preact-table/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/preact' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/preact/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/preact/table-handle' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props) { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - {state.addTableColumnBefore.canExec && ( - - Insert Left - - )} - {state.addTableColumnAfter.canExec && ( - - Insert Right - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableColumn.canExec && ( - - Delete Column - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
- - - - -
-
- - - {state.addTableRowAbove.canExec && ( - - Insert Above - - )} - {state.addTableRowBelow.canExec && ( - - Insert Below - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableRow.canExec && ( - - Delete Row - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
-
- ) -} diff --git a/preact-table/src/main.tsx b/preact-table/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-table/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-table/tsconfig.app.json b/preact-table/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-table/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-table/tsconfig.json b/preact-table/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-table/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-table/tsconfig.node.json b/preact-table/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-table/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-table/vite.config.ts b/preact-table/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-table/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-temml/.gitignore b/preact-temml/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-temml/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-temml/README.md b/preact-temml/README.md deleted file mode 100644 index 84f7440424..0000000000 --- a/preact-temml/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-temml - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-temml) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-temml) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-temml preact-temml -cd preact-temml -npm install -npm run dev -``` diff --git a/preact-temml/index.html b/preact-temml/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-temml/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-temml/package.json b/preact-temml/package.json deleted file mode 100644 index 5781e3a294..0000000000 --- a/preact-temml/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-preact-temml", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0", - "temml": "^0.13.2" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-temml/src/App.tsx b/preact-temml/src/App.tsx deleted file mode 100644 index f6ec50ec0e..0000000000 --- a/preact-temml/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/temml' - -export default function App() { - return -} diff --git a/preact-temml/src/app.css b/preact-temml/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-temml/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-temml/src/components/editor/examples/temml/editor.tsx b/preact-temml/src/components/editor/examples/temml/editor.tsx deleted file mode 100644 index 89009d34a9..0000000000 --- a/preact-temml/src/components/editor/examples/temml/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-tex' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/preact-temml/src/components/editor/examples/temml/extension.ts b/preact-temml/src/components/editor/examples/temml/extension.ts deleted file mode 100644 index 2fcd2ffa42..0000000000 --- a/preact-temml/src/components/editor/examples/temml/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderTemmlMathBlock, renderTemmlMathInline } from '../../sample/temml' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderTemmlMathBlock, - renderMathInline: renderTemmlMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-temml/src/components/editor/examples/temml/index.ts b/preact-temml/src/components/editor/examples/temml/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-temml/src/components/editor/examples/temml/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-temml/src/components/editor/sample/sample-doc-tex.ts b/preact-temml/src/components/editor/sample/sample-doc-tex.ts deleted file mode 100644 index 21ccf3e94e..0000000000 --- a/preact-temml/src/components/editor/sample/sample-doc-tex.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Inline equations' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Block equations' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: 'The Gaussian integral:' }], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - ], -} diff --git a/preact-temml/src/components/editor/sample/temml.ts b/preact-temml/src/components/editor/sample/temml.ts deleted file mode 100644 index 4cbe764f93..0000000000 --- a/preact-temml/src/components/editor/sample/temml.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Temml from 'temml' - -export function renderTemmlMathBlock(text: string, element: HTMLElement) { - Temml.render(text, element, { - displayMode: true, - annotate: true, - throwOnError: false, - }) -} - -export function renderTemmlMathInline(text: string, element: HTMLElement) { - Temml.render(text, element, { - displayMode: false, - annotate: true, - throwOnError: false, - }) -} diff --git a/preact-temml/src/main.tsx b/preact-temml/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-temml/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-temml/tsconfig.app.json b/preact-temml/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-temml/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-temml/tsconfig.json b/preact-temml/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-temml/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-temml/tsconfig.node.json b/preact-temml/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-temml/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-temml/vite.config.ts b/preact-temml/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-temml/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-text-align/.gitignore b/preact-text-align/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-text-align/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-text-align/README.md b/preact-text-align/README.md deleted file mode 100644 index 0f3b1a6c0c..0000000000 --- a/preact-text-align/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-text-align - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-text-align) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-text-align) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-text-align preact-text-align -cd preact-text-align -npm install -npm run dev -``` diff --git a/preact-text-align/index.html b/preact-text-align/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-text-align/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-text-align/package.json b/preact-text-align/package.json deleted file mode 100644 index 976daaa4a3..0000000000 --- a/preact-text-align/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-text-align", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-text-align/src/App.tsx b/preact-text-align/src/App.tsx deleted file mode 100644 index 0c049df602..0000000000 --- a/preact-text-align/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/text-align' - -export default function App() { - return -} diff --git a/preact-text-align/src/app.css b/preact-text-align/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-text-align/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-text-align/src/components/editor/examples/text-align/editor.tsx b/preact-text-align/src/components/editor/examples/text-align/editor.tsx deleted file mode 100644 index 083edee6f3..0000000000 --- a/preact-text-align/src/components/editor/examples/text-align/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-text-align' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-text-align/src/components/editor/examples/text-align/extension.ts b/preact-text-align/src/components/editor/examples/text-align/extension.ts deleted file mode 100644 index f1ae44dc7c..0000000000 --- a/preact-text-align/src/components/editor/examples/text-align/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineTextAlign } from 'prosekit/extensions/text-align' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextAlign({ types: ['paragraph', 'heading'] }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-text-align/src/components/editor/examples/text-align/index.ts b/preact-text-align/src/components/editor/examples/text-align/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-text-align/src/components/editor/examples/text-align/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-text-align/src/components/editor/examples/text-align/toolbar.tsx b/preact-text-align/src/components/editor/examples/text-align/toolbar.tsx deleted file mode 100644 index c5daf12c81..0000000000 --- a/preact-text-align/src/components/editor/examples/text-align/toolbar.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function isTextAlignActive(editor: Editor, value: string) { - return Object.values(editor.nodes).some((node) => { - // @ts-expect-error textAlign may not be available on every node - return node.isActive({ textAlign: value }) - }) -} - -function getToolbarItems(editor: Editor) { - return { - left: { - isActive: isTextAlignActive(editor, 'left'), - canExec: editor.commands.setTextAlign.canExec('left'), - command: () => editor.commands.setTextAlign('left'), - }, - center: { - isActive: isTextAlignActive(editor, 'center'), - canExec: editor.commands.setTextAlign.canExec('center'), - command: () => editor.commands.setTextAlign('center'), - }, - right: { - isActive: isTextAlignActive(editor, 'right'), - canExec: editor.commands.setTextAlign.canExec('right'), - command: () => editor.commands.setTextAlign('right'), - }, - justify: { - isActive: isTextAlignActive(editor, 'justify'), - canExec: editor.commands.setTextAlign.canExec('justify'), - command: () => editor.commands.setTextAlign('justify'), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - - - - - - -
- ) -} diff --git a/preact-text-align/src/components/editor/sample/sample-doc-text-align.ts b/preact-text-align/src/components/editor/sample/sample-doc-text-align.ts deleted file mode 100644 index 0724cea4f7..0000000000 --- a/preact-text-align/src/components/editor/sample/sample-doc-text-align.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Heading', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'left', - }, - content: [ - { - type: 'text', - text: 'First paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Second paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'right', - }, - content: [ - { - type: 'text', - text: 'Third paragraph', - }, - ], - }, - ], -} diff --git a/preact-text-align/src/components/editor/ui/button/button.tsx b/preact-text-align/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-text-align/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-text-align/src/components/editor/ui/button/index.ts b/preact-text-align/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-text-align/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-text-align/src/main.tsx b/preact-text-align/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-text-align/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-text-align/tsconfig.app.json b/preact-text-align/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-text-align/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-text-align/tsconfig.json b/preact-text-align/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-text-align/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-text-align/tsconfig.node.json b/preact-text-align/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-text-align/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-text-align/vite.config.ts b/preact-text-align/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-text-align/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-text-color/.gitignore b/preact-text-color/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-text-color/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-text-color/README.md b/preact-text-color/README.md deleted file mode 100644 index fd51bf8cdb..0000000000 --- a/preact-text-color/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-text-color - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-text-color) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-text-color) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-text-color preact-text-color -cd preact-text-color -npm install -npm run dev -``` diff --git a/preact-text-color/index.html b/preact-text-color/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-text-color/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-text-color/package.json b/preact-text-color/package.json deleted file mode 100644 index e8f702a16d..0000000000 --- a/preact-text-color/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-text-color", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-text-color/src/App.tsx b/preact-text-color/src/App.tsx deleted file mode 100644 index 1225de322a..0000000000 --- a/preact-text-color/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/text-color' - -export default function App() { - return -} diff --git a/preact-text-color/src/app.css b/preact-text-color/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-text-color/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-text-color/src/components/editor/examples/text-color/editor.tsx b/preact-text-color/src/components/editor/examples/text-color/editor.tsx deleted file mode 100644 index a3e980832a..0000000000 --- a/preact-text-color/src/components/editor/examples/text-color/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-text-color' - -import { defineExtension } from './extension' -import InlineMenu from './inline-menu' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/preact-text-color/src/components/editor/examples/text-color/extension.ts b/preact-text-color/src/components/editor/examples/text-color/extension.ts deleted file mode 100644 index d35d9d5c22..0000000000 --- a/preact-text-color/src/components/editor/examples/text-color/extension.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineBackgroundColor } from 'prosekit/extensions/background-color' -import { defineTextColor } from 'prosekit/extensions/text-color' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextColor(), - defineBackgroundColor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-text-color/src/components/editor/examples/text-color/index.ts b/preact-text-color/src/components/editor/examples/text-color/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-text-color/src/components/editor/examples/text-color/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-text-color/src/components/editor/examples/text-color/inline-menu.tsx b/preact-text-color/src/components/editor/examples/text-color/inline-menu.tsx deleted file mode 100644 index b1738229d5..0000000000 --- a/preact-text-color/src/components/editor/examples/text-color/inline-menu.tsx +++ /dev/null @@ -1,145 +0,0 @@ -import { useMemo, useState } from 'preact/hooks' -import type { Editor, Keymap } from 'prosekit/core' -import { useEditorDerivedValue, useKeymap } from 'prosekit/preact' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/preact/inline-popover' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -const textColors = [ - { label: 'Gray', value: '#9ca3af' }, - { label: 'Brown', value: '#92400e' }, - { label: 'Orange', value: '#ea580c' }, - { label: 'Yellow', value: '#ca8a04' }, - { label: 'Green', value: '#16a34a' }, - { label: 'Blue', value: '#2563eb' }, - { label: 'Purple', value: '#9333ea' }, - { label: 'Magenta', value: '#c026d3' }, - { label: 'Red', value: '#dc2626' }, -] - -const backgroundColors = [ - { label: 'Gray', value: '#f3f4f6' }, - { label: 'Brown', value: '#fef3c7' }, - { label: 'Orange', value: '#ffedd5' }, - { label: 'Yellow', value: '#fef9c3' }, - { label: 'Green', value: '#d1fae5' }, - { label: 'Blue', value: '#dbeafe' }, - { label: 'Purple', value: '#e9d5ff' }, - { label: 'Pink', value: '#fce7f3' }, - { label: 'Red', value: '#fecaca' }, -] - -function getTextColorState(editor: Editor) { - return [ - { - label: 'Default', - value: 'currentColor', - isActive: !editor.marks.textColor.isActive(), - onClick: () => editor.commands.removeTextColor(), - }, - ].concat( - textColors.map((color) => ({ - label: color.label, - value: color.value, - isActive: editor.marks.textColor.isActive({ color: color.value }), - onClick: () => editor.commands.addTextColor({ color: color.value }), - })), - ) -} - -function getBackgroundColorState(editor: Editor) { - return [ - { - label: 'Default', - value: 'canvas', - isActive: !editor.marks.backgroundColor.isActive(), - onClick: () => editor.commands.removeBackgroundColor(), - }, - ].concat( - backgroundColors.map((color) => ({ - label: color.label, - value: color.value, - isActive: editor.marks.backgroundColor.isActive({ color: color.value }), - onClick: () => editor.commands.addBackgroundColor({ color: color.value }), - })), - ) -} - -export default function InlineMenu() { - const textColorState = useEditorDerivedValue(getTextColorState) - const backgroundColorState = useEditorDerivedValue(getBackgroundColorState) - const [open, setOpen] = useState(false) - - const keymap: Keymap = useMemo( - () => ({ - Escape: () => { - if (open) { - setOpen(false) - return true - } - return false - }, - }), - [open], - ) - - useKeymap(keymap) - - return ( - setOpen(event.detail)} - > - - -
-
-
Text color
-
- {textColorState.map((color) => ( - - ))} -
-
-
-
Background color
-
- {backgroundColorState.map((color) => ( - - ))} -
-
-
-
-
-
- ) -} diff --git a/preact-text-color/src/components/editor/sample/sample-doc-text-color.ts b/preact-text-color/src/components/editor/sample/sample-doc-text-color.ts deleted file mode 100644 index a4efe4308d..0000000000 --- a/preact-text-color/src/components/editor/sample/sample-doc-text-color.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#ef4444', - }, - }, - ], - text: 'Select', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#f97316', - }, - }, - ], - text: 'some', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#eab308', - }, - }, - ], - text: 'text', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#22c55e', - }, - }, - ], - text: 'to', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#3b82f6', - }, - }, - ], - text: 'change', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#6366f1', - }, - }, - ], - text: 'the', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#a855f7', - }, - }, - ], - text: 'color', - }, - ], - }, - ], -} diff --git a/preact-text-color/src/components/editor/ui/button/button.tsx b/preact-text-color/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-text-color/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-text-color/src/components/editor/ui/button/index.ts b/preact-text-color/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-text-color/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-text-color/src/main.tsx b/preact-text-color/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-text-color/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-text-color/tsconfig.app.json b/preact-text-color/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-text-color/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-text-color/tsconfig.json b/preact-text-color/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-text-color/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-text-color/tsconfig.node.json b/preact-text-color/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-text-color/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-text-color/vite.config.ts b/preact-text-color/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-text-color/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-toolbar/.gitignore b/preact-toolbar/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-toolbar/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-toolbar/README.md b/preact-toolbar/README.md deleted file mode 100644 index af46289faa..0000000000 --- a/preact-toolbar/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-toolbar - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-toolbar) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-toolbar) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-toolbar preact-toolbar -cd preact-toolbar -npm install -npm run dev -``` diff --git a/preact-toolbar/index.html b/preact-toolbar/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-toolbar/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-toolbar/package.json b/preact-toolbar/package.json deleted file mode 100644 index 61d033d869..0000000000 --- a/preact-toolbar/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-toolbar", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-toolbar/src/App.tsx b/preact-toolbar/src/App.tsx deleted file mode 100644 index 72699e4f11..0000000000 --- a/preact-toolbar/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/toolbar' - -export default function App() { - return -} diff --git a/preact-toolbar/src/app.css b/preact-toolbar/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-toolbar/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-toolbar/src/components/editor/examples/toolbar/editor.tsx b/preact-toolbar/src/components/editor/examples/toolbar/editor.tsx deleted file mode 100644 index 8b0ef24501..0000000000 --- a/preact-toolbar/src/components/editor/examples/toolbar/editor.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleUploader } from '../../sample/sample-uploader' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-toolbar/src/components/editor/examples/toolbar/extension.ts b/preact-toolbar/src/components/editor/examples/toolbar/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/preact-toolbar/src/components/editor/examples/toolbar/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/preact-toolbar/src/components/editor/examples/toolbar/index.ts b/preact-toolbar/src/components/editor/examples/toolbar/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-toolbar/src/components/editor/examples/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-toolbar/src/components/editor/sample/sample-uploader.ts b/preact-toolbar/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/preact-toolbar/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/preact-toolbar/src/components/editor/ui/button/button.tsx b/preact-toolbar/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-toolbar/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-toolbar/src/components/editor/ui/button/index.ts b/preact-toolbar/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-toolbar/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/preact-toolbar/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-toolbar/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-toolbar/src/components/editor/ui/toolbar/index.ts b/preact-toolbar/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-toolbar/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-toolbar/src/components/editor/ui/toolbar/toolbar.tsx b/preact-toolbar/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-toolbar/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-toolbar/src/main.tsx b/preact-toolbar/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-toolbar/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-toolbar/tsconfig.app.json b/preact-toolbar/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-toolbar/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-toolbar/tsconfig.json b/preact-toolbar/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-toolbar/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-toolbar/tsconfig.node.json b/preact-toolbar/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-toolbar/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-toolbar/vite.config.ts b/preact-toolbar/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-toolbar/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-typography/.gitignore b/preact-typography/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-typography/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-typography/README.md b/preact-typography/README.md deleted file mode 100644 index f445617b64..0000000000 --- a/preact-typography/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-typography - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-typography) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-typography) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-typography preact-typography -cd preact-typography -npm install -npm run dev -``` diff --git a/preact-typography/index.html b/preact-typography/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-typography/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-typography/package.json b/preact-typography/package.json deleted file mode 100644 index 24bc1dc7db..0000000000 --- a/preact-typography/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-preact-typography", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-typography/src/App.tsx b/preact-typography/src/App.tsx deleted file mode 100644 index e1a59aa483..0000000000 --- a/preact-typography/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/typography' - -export default function App() { - return -} diff --git a/preact-typography/src/app.css b/preact-typography/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-typography/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-typography/src/components/editor/examples/typography/editor.tsx b/preact-typography/src/components/editor/examples/typography/editor.tsx deleted file mode 100644 index e078a454d9..0000000000 --- a/preact-typography/src/components/editor/examples/typography/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-typography' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/preact-typography/src/components/editor/examples/typography/extension.ts b/preact-typography/src/components/editor/examples/typography/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/preact-typography/src/components/editor/examples/typography/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-typography/src/components/editor/examples/typography/index.ts b/preact-typography/src/components/editor/examples/typography/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-typography/src/components/editor/examples/typography/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-typography/src/components/editor/sample/katex.ts b/preact-typography/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/preact-typography/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/preact-typography/src/components/editor/sample/sample-doc-typography.ts b/preact-typography/src/components/editor/sample/sample-doc-typography.ts deleted file mode 100644 index db18b8155c..0000000000 --- a/preact-typography/src/components/editor/sample/sample-doc-typography.ts +++ /dev/null @@ -1,693 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'ProseKit Typography', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This example shows the typography styles provided by ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'prosekit/basic/typography.css', - }, - { - type: 'text', - text: '.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Inline marks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Text can be formatted in different ways: ', - }, - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'bold text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'italic text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'underlined text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'strikethrough text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'inline code', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://example.com', - target: null, - rel: null, - }, - }, - ], - text: 'links', - }, - { - type: 'text', - text: ',', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'and hard breaks (Shift+Enter).', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Headings', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Heading 1', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Heading 2', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Heading 3', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 4, - }, - content: [ - { - type: 'text', - text: 'Heading 4', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 5, - }, - content: [ - { - type: 'text', - text: 'Heading 5', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 6, - }, - content: [ - { - type: 'text', - text: 'Heading 6', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Lists', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here are different types of lists:', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 1', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 2', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item A', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item B', - }, - ], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'First ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Second ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: true, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Completed task', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Pending task', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Blockquotes', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: '', - }, - content: [ - { - type: 'text', - text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Horizontal Rule', - }, - ], - }, - { - type: 'horizontalRule', - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blurred/640x360/42', - }, - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Tables', - }, - ], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 1', - }, - ], - }, - ], - }, - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 3', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 4', - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Math', - }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Inline math like Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text.' }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Block-level equations are displayed on their own line:', - }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - ], -} diff --git a/preact-typography/src/components/editor/ui/block-handle/block-handle.tsx b/preact-typography/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 8f5fe62e40..0000000000 --- a/preact-typography/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/preact/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/preact-typography/src/components/editor/ui/block-handle/index.ts b/preact-typography/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/preact-typography/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/preact-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/preact-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx deleted file mode 100644 index 6ace546a12..0000000000 --- a/preact-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { DropIndicator as BaseDropIndicator } from 'prosekit/preact/drop-indicator' - -export default function DropIndicator() { - return -} diff --git a/preact-typography/src/components/editor/ui/drop-indicator/index.ts b/preact-typography/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index f8fb7139c4..0000000000 --- a/preact-typography/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator' diff --git a/preact-typography/src/main.tsx b/preact-typography/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-typography/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-typography/tsconfig.app.json b/preact-typography/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-typography/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-typography/tsconfig.json b/preact-typography/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-typography/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-typography/tsconfig.node.json b/preact-typography/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-typography/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-typography/vite.config.ts b/preact-typography/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-typography/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-underline/.gitignore b/preact-underline/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-underline/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-underline/README.md b/preact-underline/README.md deleted file mode 100644 index f27af34743..0000000000 --- a/preact-underline/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-underline - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-underline) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-underline) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-underline preact-underline -cd preact-underline -npm install -npm run dev -``` diff --git a/preact-underline/index.html b/preact-underline/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-underline/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-underline/package.json b/preact-underline/package.json deleted file mode 100644 index e066a199d6..0000000000 --- a/preact-underline/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-underline", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-underline/src/App.tsx b/preact-underline/src/App.tsx deleted file mode 100644 index 6a03ee7870..0000000000 --- a/preact-underline/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/underline' - -export default function App() { - return -} diff --git a/preact-underline/src/app.css b/preact-underline/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-underline/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-underline/src/components/editor/examples/underline/editor.tsx b/preact-underline/src/components/editor/examples/underline/editor.tsx deleted file mode 100644 index 0125530635..0000000000 --- a/preact-underline/src/components/editor/examples/underline/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-underline' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-underline/src/components/editor/examples/underline/extension.ts b/preact-underline/src/components/editor/examples/underline/extension.ts deleted file mode 100644 index 16a9b58284..0000000000 --- a/preact-underline/src/components/editor/examples/underline/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineUnderline(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-underline/src/components/editor/examples/underline/index.ts b/preact-underline/src/components/editor/examples/underline/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-underline/src/components/editor/examples/underline/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-underline/src/components/editor/sample/sample-doc-underline.ts b/preact-underline/src/components/editor/sample/sample-doc-underline.ts deleted file mode 100644 index 6af561064b..0000000000 --- a/preact-underline/src/components/editor/sample/sample-doc-underline.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'This is underline', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/preact-underline/src/components/editor/ui/button/button.tsx b/preact-underline/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-underline/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-underline/src/components/editor/ui/button/index.ts b/preact-underline/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-underline/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-underline/src/components/editor/ui/image-upload-popover/index.ts b/preact-underline/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-underline/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-underline/src/components/editor/ui/toolbar/index.ts b/preact-underline/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-underline/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-underline/src/components/editor/ui/toolbar/toolbar.tsx b/preact-underline/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-underline/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-underline/src/main.tsx b/preact-underline/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-underline/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-underline/tsconfig.app.json b/preact-underline/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-underline/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-underline/tsconfig.json b/preact-underline/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-underline/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-underline/tsconfig.node.json b/preact-underline/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-underline/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-underline/vite.config.ts b/preact-underline/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-underline/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-unmount/.gitignore b/preact-unmount/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-unmount/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-unmount/README.md b/preact-unmount/README.md deleted file mode 100644 index 414d115d56..0000000000 --- a/preact-unmount/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-unmount - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-unmount) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-unmount) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-unmount preact-unmount -cd preact-unmount -npm install -npm run dev -``` diff --git a/preact-unmount/index.html b/preact-unmount/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-unmount/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-unmount/package.json b/preact-unmount/package.json deleted file mode 100644 index 09feac1f1b..0000000000 --- a/preact-unmount/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-unmount", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-unmount/src/App.tsx b/preact-unmount/src/App.tsx deleted file mode 100644 index da35bea56f..0000000000 --- a/preact-unmount/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/unmount' - -export default function App() { - return -} diff --git a/preact-unmount/src/app.css b/preact-unmount/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-unmount/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-unmount/src/components/editor/examples/unmount/editor-component.tsx b/preact-unmount/src/components/editor/examples/unmount/editor-component.tsx deleted file mode 100644 index 975a584f21..0000000000 --- a/preact-unmount/src/components/editor/examples/unmount/editor-component.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { InlineMenu } from '../../ui/inline-menu' - -import ExtensionComponent from './extension-component' - -export default function EditorComponent(props: { placeholder: string }) { - const editor = useMemo(() => { - return createEditor({ extension: defineBasicExtension() }) - }, []) - - return ( - -
-
-
- -
-
- -
- ) -} diff --git a/preact-unmount/src/components/editor/examples/unmount/editor.tsx b/preact-unmount/src/components/editor/examples/unmount/editor.tsx deleted file mode 100644 index d54f0a7591..0000000000 --- a/preact-unmount/src/components/editor/examples/unmount/editor.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useCallback, useRef, useState } from 'preact/hooks' - -import EditorComponent from './editor-component' - -function EditorGroup() { - const nextKeyRef = useRef(1) - const [editorKeys, setEditorKeys] = useState([]) - - const addEditor = useCallback(() => { - const key = nextKeyRef.current - nextKeyRef.current += 1 - setEditorKeys((keys) => [...keys, key]) - }, []) - - const removeEditor = useCallback((key: number) => { - setEditorKeys((keys) => keys.filter((k) => k !== key)) - }, []) - - return ( -
-
- - {editorKeys.map((key) => ( - - ))} -
- {editorKeys.map((key) => ( -
- -
- ))} -
- ) -} - -export default EditorGroup diff --git a/preact-unmount/src/components/editor/examples/unmount/extension-component.tsx b/preact-unmount/src/components/editor/examples/unmount/extension-component.tsx deleted file mode 100644 index d5c811532f..0000000000 --- a/preact-unmount/src/components/editor/examples/unmount/extension-component.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useMemo } from 'preact/hooks' -import { definePlaceholder } from 'prosekit/extensions/placeholder' -import { useExtension } from 'prosekit/preact' - -export default function ExtensionComponent(props: { placeholder: string }) { - const extension = useMemo( - () => definePlaceholder({ placeholder: props.placeholder }), - [props.placeholder], - ) - - useExtension(extension) - - return null -} diff --git a/preact-unmount/src/components/editor/examples/unmount/index.ts b/preact-unmount/src/components/editor/examples/unmount/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-unmount/src/components/editor/examples/unmount/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-unmount/src/components/editor/ui/button/button.tsx b/preact-unmount/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-unmount/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-unmount/src/components/editor/ui/button/index.ts b/preact-unmount/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-unmount/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-unmount/src/components/editor/ui/inline-menu/index.ts b/preact-unmount/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/preact-unmount/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/preact-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index a014b74f57..0000000000 --- a/preact-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -import type { JSX } from 'preact' -import { useState } from 'preact/hooks' -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/preact' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/preact/inline-popover' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - const handleSubmit = ( - event: JSX.TargetedEvent, - ) => { - event.preventDefault() - const href = event.currentTarget.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
- -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/preact-unmount/src/main.tsx b/preact-unmount/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-unmount/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-unmount/tsconfig.app.json b/preact-unmount/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-unmount/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-unmount/tsconfig.json b/preact-unmount/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-unmount/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-unmount/tsconfig.node.json b/preact-unmount/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-unmount/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-unmount/vite.config.ts b/preact-unmount/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-unmount/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-user-menu-dynamic/.gitignore b/preact-user-menu-dynamic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-user-menu-dynamic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-user-menu-dynamic/README.md b/preact-user-menu-dynamic/README.md deleted file mode 100644 index 491cefb490..0000000000 --- a/preact-user-menu-dynamic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-user-menu-dynamic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-user-menu-dynamic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-user-menu-dynamic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-user-menu-dynamic preact-user-menu-dynamic -cd preact-user-menu-dynamic -npm install -npm run dev -``` diff --git a/preact-user-menu-dynamic/index.html b/preact-user-menu-dynamic/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-user-menu-dynamic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-user-menu-dynamic/package.json b/preact-user-menu-dynamic/package.json deleted file mode 100644 index b313be6d61..0000000000 --- a/preact-user-menu-dynamic/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-user-menu-dynamic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-user-menu-dynamic/src/App.tsx b/preact-user-menu-dynamic/src/App.tsx deleted file mode 100644 index e3ec0e7b10..0000000000 --- a/preact-user-menu-dynamic/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/user-menu-dynamic' - -export default function App() { - return -} diff --git a/preact-user-menu-dynamic/src/app.css b/preact-user-menu-dynamic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-user-menu-dynamic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx deleted file mode 100644 index 17d6c2f85a..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { defineExtension } from './extension' -import UserMenuDynamic from './user-menu-dynamic' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts deleted file mode 100644 index ff2c40b104..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts deleted file mode 100644 index 06176376bd..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { useEffect, useState } from 'preact/hooks' - -import type { User } from '../../sample/sample-query-users' -import { queryUsers } from '../../sample/sample-query-users' - -/** - * Simulate a user searching with some delay. - */ -export function useUserQuery(query: string, enabled: boolean) { - const [users, setUsers] = useState([]) - const [loading, setLoading] = useState(true) - - if (!enabled && users.length > 0) { - setUsers([]) - } - - useEffect(() => { - if (!enabled) { - return - } - - let cancelled = false - - void (async () => { - setLoading(true) - const filteredUsers = await queryUsers(query) - if (cancelled) { - return - } - setUsers(filteredUsers) - setLoading(false) - })() - - return () => { - cancelled = true - } - }, [enabled, query]) - - return { loading, users } -} diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx deleted file mode 100644 index 18fc7611b1..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { useState } from 'preact/hooks' - -import { UserMenu } from '../../ui/user-menu' - -import { useUserQuery } from './use-user-query' - -export default function UserMenuDynamic() { - const [query, setQuery] = useState('') - const [open, setOpen] = useState(false) - - const { loading, users } = useUserQuery(query, open) - - return ( - - ) -} diff --git a/preact-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/preact-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts deleted file mode 100644 index ab78fd5525..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { users } from './sample-user-data' - -export interface User { - id: number - name: string -} - -const connectHandlers: VoidFunction[] = [] -let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' - -/** - * A utility function to simulate different network states. Useful for testing. - * - * @internal - */ -export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { - networkStatus = status - if (status !== 'offline') { - connectHandlers.forEach((handler) => handler()) - connectHandlers.length = 0 - } -} - -/** - * Simulate a user searching with some delay. - */ -export async function queryUsers(query: string): Promise { - if (networkStatus === 'offline') { - await new Promise((resolve) => connectHandlers.push(resolve)) - } - if (networkStatus === 'slow') { - await new Promise((resolve) => setTimeout(resolve, 300)) - } - - const normalizedQuery = query.toLowerCase().trim() - const filteredUsers = users - .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) - .slice(0, 10) - return filteredUsers -} diff --git a/preact-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/preact-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/preact-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/preact-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/preact-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx b/preact-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 39b78adbde..0000000000 --- a/preact-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/preact' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/preact/autocomplete' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}) { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - {props.users.map((user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - ))} -
-
-
-
- ) -} diff --git a/preact-user-menu-dynamic/src/main.tsx b/preact-user-menu-dynamic/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-user-menu-dynamic/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-user-menu-dynamic/tsconfig.app.json b/preact-user-menu-dynamic/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-user-menu-dynamic/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-user-menu-dynamic/tsconfig.json b/preact-user-menu-dynamic/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-user-menu-dynamic/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-user-menu-dynamic/tsconfig.node.json b/preact-user-menu-dynamic/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-user-menu-dynamic/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-user-menu-dynamic/vite.config.ts b/preact-user-menu-dynamic/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-user-menu-dynamic/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-user-menu/.gitignore b/preact-user-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-user-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-user-menu/README.md b/preact-user-menu/README.md deleted file mode 100644 index 0d439b55a2..0000000000 --- a/preact-user-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-user-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-user-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-user-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-user-menu preact-user-menu -cd preact-user-menu -npm install -npm run dev -``` diff --git a/preact-user-menu/index.html b/preact-user-menu/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-user-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-user-menu/package.json b/preact-user-menu/package.json deleted file mode 100644 index 69b58f970e..0000000000 --- a/preact-user-menu/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-user-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-user-menu/src/App.tsx b/preact-user-menu/src/App.tsx deleted file mode 100644 index 92fca03d42..0000000000 --- a/preact-user-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/user-menu' - -export default function App() { - return -} diff --git a/preact-user-menu/src/app.css b/preact-user-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-user-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-user-menu/src/components/editor/examples/user-menu/editor.tsx b/preact-user-menu/src/components/editor/examples/user-menu/editor.tsx deleted file mode 100644 index 2cdd458403..0000000000 --- a/preact-user-menu/src/components/editor/examples/user-menu/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { tags } from '../../sample/sample-tag-data' -import { users } from '../../sample/sample-user-data' -import { TagMenu } from '../../ui/tag-menu' -import { UserMenu } from '../../ui/user-menu' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/preact-user-menu/src/components/editor/examples/user-menu/extension.ts b/preact-user-menu/src/components/editor/examples/user-menu/extension.ts deleted file mode 100644 index 56a97a4779..0000000000 --- a/preact-user-menu/src/components/editor/examples/user-menu/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone or # to tag something...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/preact-user-menu/src/components/editor/examples/user-menu/index.ts b/preact-user-menu/src/components/editor/examples/user-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-user-menu/src/components/editor/examples/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-user-menu/src/components/editor/sample/sample-tag-data.ts b/preact-user-menu/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/preact-user-menu/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/preact-user-menu/src/components/editor/sample/sample-user-data.ts b/preact-user-menu/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/preact-user-menu/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/preact-user-menu/src/components/editor/ui/tag-menu/index.ts b/preact-user-menu/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index d344b33a70..0000000000 --- a/preact-user-menu/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu' diff --git a/preact-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx b/preact-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx deleted file mode 100644 index 00b3e4b085..0000000000 --- a/preact-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/preact' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/preact/autocomplete' - -const regex = /#[\da-z]*$/i - -export default function TagMenu(props: { - tags: { id: number; label: string }[] -}) { - const editor = useEditor>() - - const handleTagInsert = (id: number, label: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '#' + label, - kind: 'tag', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - - - -
- - No results - - - {props.tags.map((tag) => ( - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - ))} -
-
-
-
- ) -} diff --git a/preact-user-menu/src/components/editor/ui/user-menu/index.ts b/preact-user-menu/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/preact-user-menu/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/preact-user-menu/src/components/editor/ui/user-menu/user-menu.tsx b/preact-user-menu/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 39b78adbde..0000000000 --- a/preact-user-menu/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/preact' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/preact/autocomplete' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}) { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - {props.users.map((user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - ))} -
-
-
-
- ) -} diff --git a/preact-user-menu/src/main.tsx b/preact-user-menu/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-user-menu/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-user-menu/tsconfig.app.json b/preact-user-menu/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-user-menu/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-user-menu/tsconfig.json b/preact-user-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-user-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-user-menu/tsconfig.node.json b/preact-user-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-user-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-user-menu/vite.config.ts b/preact-user-menu/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-user-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-word-counter/.gitignore b/preact-word-counter/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-word-counter/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-word-counter/README.md b/preact-word-counter/README.md deleted file mode 100644 index 1f6eb025dc..0000000000 --- a/preact-word-counter/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-word-counter - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-word-counter) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-word-counter) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-word-counter preact-word-counter -cd preact-word-counter -npm install -npm run dev -``` diff --git a/preact-word-counter/index.html b/preact-word-counter/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-word-counter/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-word-counter/package.json b/preact-word-counter/package.json deleted file mode 100644 index 8fde8484a0..0000000000 --- a/preact-word-counter/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-preact-word-counter", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-word-counter/src/App.tsx b/preact-word-counter/src/App.tsx deleted file mode 100644 index 9da98dddb5..0000000000 --- a/preact-word-counter/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/word-counter' - -export default function App() { - return -} diff --git a/preact-word-counter/src/app.css b/preact-word-counter/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-word-counter/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-word-counter/src/components/editor/examples/word-counter/editor.tsx b/preact-word-counter/src/components/editor/examples/word-counter/editor.tsx deleted file mode 100644 index a4249ea763..0000000000 --- a/preact-word-counter/src/components/editor/examples/word-counter/editor.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { useMemo } from 'preact/hooks' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' - -import { sampleContent } from '../../sample/sample-doc-word-counter' -import { WordCounter } from '../../ui/word-counter' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ - extension, - defaultContent, - }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/preact-word-counter/src/components/editor/examples/word-counter/extension.ts b/preact-word-counter/src/components/editor/examples/word-counter/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/preact-word-counter/src/components/editor/examples/word-counter/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/preact-word-counter/src/components/editor/examples/word-counter/index.ts b/preact-word-counter/src/components/editor/examples/word-counter/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-word-counter/src/components/editor/examples/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/preact-word-counter/src/components/editor/sample/sample-doc-word-counter.ts deleted file mode 100644 index 0b5d435038..0000000000 --- a/preact-word-counter/src/components/editor/sample/sample-doc-word-counter.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Start typing and observe the word count update below.', - }, - ], - }, - ], -} diff --git a/preact-word-counter/src/components/editor/ui/word-counter/index.ts b/preact-word-counter/src/components/editor/ui/word-counter/index.ts deleted file mode 100644 index 929ee3e41a..0000000000 --- a/preact-word-counter/src/components/editor/ui/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as WordCounter } from './word-counter' diff --git a/preact-word-counter/src/components/editor/ui/word-counter/word-counter.tsx b/preact-word-counter/src/components/editor/ui/word-counter/word-counter.tsx deleted file mode 100644 index 53d8f88097..0000000000 --- a/preact-word-counter/src/components/editor/ui/word-counter/word-counter.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/preact' - -function getWordCount(editor: Editor) { - const doc = editor.state.doc - const words = doc ? doc.textBetween(0, doc.content.size, ' ') : '' - const wordCount = words.split(/\s+/).filter((s) => s).length - const characterCount = doc ? doc.textContent.length : 0 - return { wordCount, characterCount } -} - -export default function WordCounter() { - const { wordCount, characterCount } = useEditorDerivedValue(getWordCount) - - return ( -
- Word Count: {wordCount} -
- Character Count: {characterCount} -
- ) -} diff --git a/preact-word-counter/src/main.tsx b/preact-word-counter/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-word-counter/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-word-counter/tsconfig.app.json b/preact-word-counter/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-word-counter/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-word-counter/tsconfig.json b/preact-word-counter/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-word-counter/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-word-counter/tsconfig.node.json b/preact-word-counter/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-word-counter/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-word-counter/vite.config.ts b/preact-word-counter/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-word-counter/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/preact-yjs/.gitignore b/preact-yjs/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/preact-yjs/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/preact-yjs/README.md b/preact-yjs/README.md deleted file mode 100644 index f973bc3abc..0000000000 --- a/preact-yjs/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# preact-yjs - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-yjs) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-yjs) - -Run the example locally with: - -```bash -npx degit prosekit/examples/preact-yjs preact-yjs -cd preact-yjs -npm install -npm run dev -``` diff --git a/preact-yjs/index.html b/preact-yjs/index.html deleted file mode 100644 index b4f79f2233..0000000000 --- a/preact-yjs/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Preact - - -
- - - diff --git a/preact-yjs/package.json b/preact-yjs/package.json deleted file mode 100644 index 3308ece64b..0000000000 --- a/preact-yjs/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-preact-yjs", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "preact": "^10.29.1", - "prosekit": "^0.21.0", - "y-prosemirror": "^1.3.7", - "y-protocols": "^1.0.7", - "y-websocket": "^3.0.0", - "yjs": "^13.6.30" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@preact/preset-vite": "^2.10.5", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/preact-yjs/src/App.tsx b/preact-yjs/src/App.tsx deleted file mode 100644 index 8641aefe47..0000000000 --- a/preact-yjs/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/yjs' - -export default function App() { - return -} diff --git a/preact-yjs/src/app.css b/preact-yjs/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/preact-yjs/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/preact-yjs/src/components/editor/examples/yjs/editor-component.tsx b/preact-yjs/src/components/editor/examples/yjs/editor-component.tsx deleted file mode 100644 index e5385a4ca3..0000000000 --- a/preact-yjs/src/components/editor/examples/yjs/editor-component.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/yjs/style.css' - -import { useMemo } from 'preact/hooks' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/preact' -import { WebsocketProvider } from 'y-websocket' -import * as Y from 'yjs' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function EditorComponent(props: { room?: string }) { - const editor = useMemo(() => { - const doc = new Y.Doc() - const provider = new WebsocketProvider( - 'wss://demos.yjs.dev/ws', - `github.com/prosekit/room_${props.room}`, - doc, - ) - - const extension = defineExtension(doc, provider.awareness) - return createEditor({ extension }) - }, [props.room]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/preact-yjs/src/components/editor/examples/yjs/editor.tsx b/preact-yjs/src/components/editor/examples/yjs/editor.tsx deleted file mode 100644 index be276b5b1d..0000000000 --- a/preact-yjs/src/components/editor/examples/yjs/editor.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { useState } from 'preact/hooks' - -import EditorComponent from './editor-component' - -export default function Page() { - const [room] = useState(() => { - return Math.random().toString(36).substring(2, 15) - }) - - return ( -
- - -
- ) -} diff --git a/preact-yjs/src/components/editor/examples/yjs/extension.ts b/preact-yjs/src/components/editor/examples/yjs/extension.ts deleted file mode 100644 index f1a581932b..0000000000 --- a/preact-yjs/src/components/editor/examples/yjs/extension.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' -import { defineYjs } from 'prosekit/extensions/yjs' -import type { Awareness } from 'prosekit/extensions/yjs' -import type * as Y from 'yjs' - -export function defineExtension(doc: Y.Doc, awareness: Awareness) { - return union([ - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineYjs({ doc, awareness }), - ]) -} - -export type EditorExtension = ReturnType diff --git a/preact-yjs/src/components/editor/examples/yjs/index.ts b/preact-yjs/src/components/editor/examples/yjs/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/preact-yjs/src/components/editor/examples/yjs/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/preact-yjs/src/components/editor/ui/button/button.tsx b/preact-yjs/src/components/editor/ui/button/button.tsx deleted file mode 100644 index 8df85bcb7d..0000000000 --- a/preact-yjs/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import type { ComponentChild, MouseEventHandler } from 'preact' -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/preact/tooltip' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ComponentChild -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/preact-yjs/src/components/editor/ui/button/index.ts b/preact-yjs/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/preact-yjs/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/preact-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 764667a8c0..0000000000 --- a/preact-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { ComponentChild, JSX } from 'preact' -import { useId, useState } from 'preact/hooks' -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/preact' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/preact/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ComponentChild -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange = ( - event: JSX.TargetedEvent, - ) => { - const file = event.currentTarget.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = ( - event: JSX.TargetedEvent, - ) => { - const url = event.currentTarget.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/preact-yjs/src/components/editor/ui/image-upload-popover/index.ts b/preact-yjs/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/preact-yjs/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-yjs/src/components/editor/ui/toolbar/index.ts b/preact-yjs/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/preact-yjs/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/preact-yjs/src/components/editor/ui/toolbar/toolbar.tsx b/preact-yjs/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index 746a58435a..0000000000 --- a/preact-yjs/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,363 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/preact' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/preact-yjs/src/main.tsx b/preact-yjs/src/main.tsx deleted file mode 100644 index 9452b5673a..0000000000 --- a/preact-yjs/src/main.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { render } from 'preact' -import App from './App.tsx' - -render(, document.getElementById('app')!) diff --git a/preact-yjs/tsconfig.app.json b/preact-yjs/tsconfig.app.json deleted file mode 100644 index 3fe3ab979d..0000000000 --- a/preact-yjs/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - "paths": { - "react": ["./node_modules/preact/compat/"], - "react-dom": ["./node_modules/preact/compat/"] - }, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - "jsxImportSource": "preact", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/preact-yjs/tsconfig.json b/preact-yjs/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/preact-yjs/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/preact-yjs/tsconfig.node.json b/preact-yjs/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/preact-yjs/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/preact-yjs/vite.config.ts b/preact-yjs/vite.config.ts deleted file mode 100644 index 5e0b3c9e1a..0000000000 --- a/preact-yjs/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import preact from '@preact/preset-vite' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [preact(), tailwindcss()], -}) diff --git a/react-block-handle/.gitignore b/react-block-handle/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-block-handle/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-block-handle/README.md b/react-block-handle/README.md deleted file mode 100644 index 4d954899ce..0000000000 --- a/react-block-handle/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-block-handle - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-block-handle) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-block-handle) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-block-handle react-block-handle -cd react-block-handle -npm install -npm run dev -``` diff --git a/react-block-handle/index.html b/react-block-handle/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-block-handle/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-block-handle/package.json b/react-block-handle/package.json deleted file mode 100644 index bd38922d46..0000000000 --- a/react-block-handle/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-block-handle", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-block-handle/src/App.tsx b/react-block-handle/src/App.tsx deleted file mode 100644 index 2cb5b6bb8d..0000000000 --- a/react-block-handle/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/block-handle' - -export default function App() { - return -} diff --git a/react-block-handle/src/app.css b/react-block-handle/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-block-handle/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-block-handle/src/components/editor/examples/block-handle/editor.tsx b/react-block-handle/src/components/editor/examples/block-handle/editor.tsx deleted file mode 100644 index b6512f948e..0000000000 --- a/react-block-handle/src/components/editor/examples/block-handle/editor.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-block-handle' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/react-block-handle/src/components/editor/examples/block-handle/extension.ts b/react-block-handle/src/components/editor/examples/block-handle/extension.ts deleted file mode 100644 index 2c6a5383ad..0000000000 --- a/react-block-handle/src/components/editor/examples/block-handle/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union([defineBasicExtension(), defineCodeBlockView()]) -} - -export type EditorExtension = ReturnType diff --git a/react-block-handle/src/components/editor/examples/block-handle/index.ts b/react-block-handle/src/components/editor/examples/block-handle/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-block-handle/src/components/editor/examples/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/react-block-handle/src/components/editor/sample/sample-doc-block-handle.ts deleted file mode 100644 index 3c6ccdc203..0000000000 --- a/react-block-handle/src/components/editor/sample/sample-doc-block-handle.ts +++ /dev/null @@ -1,323 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Drag and Drop Demo', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Getting Started', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This paragraph can be moved above or below other blocks.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Different Block Types', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'You can drag paragraphs, headings, lists, code blocks, and more.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Lists Work Too', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This entire list can be dragged', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Individual list items stay together', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try moving this list around', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Ordered lists also support dragging', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The numbering updates automatically', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag this list to see it in action', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Even code blocks can be moved:', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: 'javascript', - }, - content: [ - { - type: 'text', - text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Nested Content', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This blockquote can be moved as a single unit.', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested blockquotes move together with their parent.', - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Try It Yourself', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Practice by moving this paragraph to the top of the document.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Or drag this one to between the headings above.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The drag handles make it easy to reorganize your content exactly how you want it.', - }, - ], - }, - ], -} diff --git a/react-block-handle/src/components/editor/ui/block-handle/block-handle.tsx b/react-block-handle/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 3cc6028d5c..0000000000 --- a/react-block-handle/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' - -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/react/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/react-block-handle/src/components/editor/ui/block-handle/index.ts b/react-block-handle/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/react-block-handle/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/react-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx b/react-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index f6c0428091..0000000000 --- a/react-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { ReactNodeViewProps } from 'prosekit/react' - -export default function CodeBlockView(props: ReactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/react-block-handle/src/components/editor/ui/code-block-view/index.ts b/react-block-handle/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index b7e6b996bc..0000000000
--- a/react-block-handle/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineReactNodeView,
-  type ReactNodeViewComponent,
-} from 'prosekit/react'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineReactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies ReactNodeViewComponent,
-  })
-}
diff --git a/react-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/react-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
deleted file mode 100644
index 87c1746622..0000000000
--- a/react-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-'use client'
-
-import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator'
-
-export default function DropIndicator() {
-  return 
-}
diff --git a/react-block-handle/src/components/editor/ui/drop-indicator/index.ts b/react-block-handle/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index f8fb7139c4..0000000000
--- a/react-block-handle/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator'
diff --git a/react-block-handle/src/main.tsx b/react-block-handle/src/main.tsx
deleted file mode 100644
index 87de8eb52b..0000000000
--- a/react-block-handle/src/main.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import './app.css'
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import App from './App.tsx'
-
-ReactDOM.createRoot(document.getElementById('root')!).render(
-  
-    
-  ,
-)
diff --git a/react-block-handle/tsconfig.app.json b/react-block-handle/tsconfig.app.json
deleted file mode 100644
index a9b5a59ca6..0000000000
--- a/react-block-handle/tsconfig.app.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
-    "target": "ES2022",
-    "useDefineForClassFields": true,
-    "lib": ["ES2022", "DOM", "DOM.Iterable"],
-    "module": "ESNext",
-    "types": ["vite/client"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-    "jsx": "react-jsx",
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["src"]
-}
diff --git a/react-block-handle/tsconfig.json b/react-block-handle/tsconfig.json
deleted file mode 100644
index 1ffef600d9..0000000000
--- a/react-block-handle/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "files": [],
-  "references": [
-    { "path": "./tsconfig.app.json" },
-    { "path": "./tsconfig.node.json" }
-  ]
-}
diff --git a/react-block-handle/tsconfig.node.json b/react-block-handle/tsconfig.node.json
deleted file mode 100644
index 8a67f62f4c..0000000000
--- a/react-block-handle/tsconfig.node.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
-    "target": "ES2023",
-    "lib": ["ES2023"],
-    "module": "ESNext",
-    "types": ["node"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/react-block-handle/vite.config.ts b/react-block-handle/vite.config.ts
deleted file mode 100644
index c90997597d..0000000000
--- a/react-block-handle/vite.config.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
-import tailwindcss from '@tailwindcss/vite'
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  plugins: [react(), tailwindcss()],
-})
diff --git a/react-blockquote/.gitignore b/react-blockquote/.gitignore
deleted file mode 100644
index 5d6225c6df..0000000000
--- a/react-blockquote/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-dist
-.next
-.svelte-kit
diff --git a/react-blockquote/README.md b/react-blockquote/README.md
deleted file mode 100644
index 93713fd42d..0000000000
--- a/react-blockquote/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# react-blockquote
-
-A [ProseKit](https://prosekit.dev) example.
-
-[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-blockquote)
-[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-blockquote)
-
-Run the example locally with:
-
-```bash
-npx degit prosekit/examples/react-blockquote react-blockquote
-cd react-blockquote
-npm install
-npm run dev
-```
diff --git a/react-blockquote/index.html b/react-blockquote/index.html
deleted file mode 100644
index a5a78f3bf8..0000000000
--- a/react-blockquote/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-  
-    
-    
-    ProseKit + React
-  
-  
-    
- - - diff --git a/react-blockquote/package.json b/react-blockquote/package.json deleted file mode 100644 index eb2c784b90..0000000000 --- a/react-blockquote/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-blockquote", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-blockquote/src/App.tsx b/react-blockquote/src/App.tsx deleted file mode 100644 index 3327cfcf2d..0000000000 --- a/react-blockquote/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/blockquote' - -export default function App() { - return -} diff --git a/react-blockquote/src/app.css b/react-blockquote/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-blockquote/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-blockquote/src/components/editor/examples/blockquote/editor.tsx b/react-blockquote/src/components/editor/examples/blockquote/editor.tsx deleted file mode 100644 index cbf25168cf..0000000000 --- a/react-blockquote/src/components/editor/examples/blockquote/editor.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - return createEditor({ extension: defineExtension() }) - }, []) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-blockquote/src/components/editor/examples/blockquote/extension.ts b/react-blockquote/src/components/editor/examples/blockquote/extension.ts deleted file mode 100644 index 5292b59e35..0000000000 --- a/react-blockquote/src/components/editor/examples/blockquote/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBlockquote(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-blockquote/src/components/editor/examples/blockquote/index.ts b/react-blockquote/src/components/editor/examples/blockquote/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-blockquote/src/components/editor/examples/blockquote/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-blockquote/src/components/editor/ui/button/button.tsx b/react-blockquote/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-blockquote/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-blockquote/src/components/editor/ui/button/index.ts b/react-blockquote/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-blockquote/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/react-blockquote/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-blockquote/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-blockquote/src/components/editor/ui/toolbar/index.ts b/react-blockquote/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-blockquote/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-blockquote/src/components/editor/ui/toolbar/toolbar.tsx b/react-blockquote/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-blockquote/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-blockquote/src/main.tsx b/react-blockquote/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-blockquote/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-blockquote/tsconfig.app.json b/react-blockquote/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-blockquote/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-blockquote/tsconfig.json b/react-blockquote/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-blockquote/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-blockquote/tsconfig.node.json b/react-blockquote/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-blockquote/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-blockquote/vite.config.ts b/react-blockquote/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-blockquote/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-bold/.gitignore b/react-bold/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-bold/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-bold/README.md b/react-bold/README.md deleted file mode 100644 index dec2aa3c99..0000000000 --- a/react-bold/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-bold - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-bold) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-bold) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-bold react-bold -cd react-bold -npm install -npm run dev -``` diff --git a/react-bold/index.html b/react-bold/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-bold/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-bold/package.json b/react-bold/package.json deleted file mode 100644 index 0565ff79e7..0000000000 --- a/react-bold/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-bold", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-bold/src/App.tsx b/react-bold/src/App.tsx deleted file mode 100644 index 274955047d..0000000000 --- a/react-bold/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/bold' - -export default function App() { - return -} diff --git a/react-bold/src/app.css b/react-bold/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-bold/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-bold/src/components/editor/examples/bold/editor.tsx b/react-bold/src/components/editor/examples/bold/editor.tsx deleted file mode 100644 index 4fed923fec..0000000000 --- a/react-bold/src/components/editor/examples/bold/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-bold' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-bold/src/components/editor/examples/bold/extension.ts b/react-bold/src/components/editor/examples/bold/extension.ts deleted file mode 100644 index eaa4fba721..0000000000 --- a/react-bold/src/components/editor/examples/bold/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBold } from 'prosekit/extensions/bold' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBold(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-bold/src/components/editor/examples/bold/index.ts b/react-bold/src/components/editor/examples/bold/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-bold/src/components/editor/examples/bold/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-bold/src/components/editor/sample/sample-doc-bold.ts b/react-bold/src/components/editor/sample/sample-doc-bold.ts deleted file mode 100644 index 09ed08daad..0000000000 --- a/react-bold/src/components/editor/sample/sample-doc-bold.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/react-bold/src/components/editor/ui/button/button.tsx b/react-bold/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-bold/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-bold/src/components/editor/ui/button/index.ts b/react-bold/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-bold/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-bold/src/components/editor/ui/image-upload-popover/index.ts b/react-bold/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-bold/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-bold/src/components/editor/ui/toolbar/index.ts b/react-bold/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-bold/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-bold/src/components/editor/ui/toolbar/toolbar.tsx b/react-bold/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-bold/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-bold/src/main.tsx b/react-bold/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-bold/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-bold/tsconfig.app.json b/react-bold/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-bold/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-bold/tsconfig.json b/react-bold/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-bold/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-bold/tsconfig.node.json b/react-bold/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-bold/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-bold/vite.config.ts b/react-bold/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-bold/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-change-tracking/.gitignore b/react-change-tracking/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-change-tracking/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-change-tracking/README.md b/react-change-tracking/README.md deleted file mode 100644 index adb28d3ffc..0000000000 --- a/react-change-tracking/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-change-tracking - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-change-tracking) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-change-tracking) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-change-tracking react-change-tracking -cd react-change-tracking -npm install -npm run dev -``` diff --git a/react-change-tracking/index.html b/react-change-tracking/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-change-tracking/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-change-tracking/package.json b/react-change-tracking/package.json deleted file mode 100644 index 16a65a985d..0000000000 --- a/react-change-tracking/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-change-tracking", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-change-tracking/src/App.tsx b/react-change-tracking/src/App.tsx deleted file mode 100644 index 88160e69c9..0000000000 --- a/react-change-tracking/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/change-tracking' - -export default function App() { - return -} diff --git a/react-change-tracking/src/app.css b/react-change-tracking/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-change-tracking/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx b/react-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx deleted file mode 100644 index 80f3378002..0000000000 --- a/react-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, union } from 'prosekit/core' -import { defineCommitViewer, type Commit } from 'prosekit/extensions/commit' -import { defineReadonly } from 'prosekit/extensions/readonly' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -export default function EditorDiff(props: { commit: Commit }) { - const editor = useMemo(() => { - const extension = union( - defineBasicExtension(), - defineReadonly(), - defineCommitViewer(props.commit), - ) - return createEditor({ extension }) - }, [props.commit]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx b/react-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx deleted file mode 100644 index 61ff6200cf..0000000000 --- a/react-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, union, type NodeJSON } from 'prosekit/core' -import { - defineCommitRecorder, - type CommitRecorder, -} from 'prosekit/extensions/commit' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -export default function EditorMain(props: { - commitRecorder: CommitRecorder - initialContent?: NodeJSON -}) { - const editor = useMemo(() => { - const extension = union( - defineBasicExtension(), - defineCommitRecorder(props.commitRecorder), - ) - return createEditor({ extension, defaultContent: props.initialContent }) - }, [props.commitRecorder, props.initialContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-change-tracking/src/components/editor/examples/change-tracking/editor.tsx b/react-change-tracking/src/components/editor/examples/change-tracking/editor.tsx deleted file mode 100644 index 131c865c37..0000000000 --- a/react-change-tracking/src/components/editor/examples/change-tracking/editor.tsx +++ /dev/null @@ -1,80 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import type { NodeJSON } from 'prosekit/core' -import { CommitRecorder, type Commit } from 'prosekit/extensions/commit' -import { useCallback, useMemo, useState } from 'react' - -import EditorDiff from './editor-diff' -import EditorMain from './editor-main' - -export default function Editor() { - const [commits, setCommits] = useState< - { id: string; date: Date; commit: Commit }[] - >([]) - const [key, setKey] = useState(0) - const [initialContent, setInitialContent] = useState() - const commitRecorder = useMemo(() => new CommitRecorder(), []) - - const handleCommit = useCallback(() => { - const commit = commitRecorder.commit() - if (!commit) return - const id = Math.random().toString(36).slice(2, 9) - setCommits((commits) => [{ id, date: new Date(), commit }, ...commits]) - }, [commitRecorder]) - - const handleRestore = useCallback( - (id: string) => { - const index = commits.findIndex((commit) => commit.id === id) - const commit = commits[index] - if (index === -1 || !commit) return - const doc = commit.commit.doc - setInitialContent(doc) - setCommits((commits) => commits.slice(index)) - setKey((key) => key + 1) - }, - [commits], - ) - - return ( -
-
-
- -
- -
-
- {commits.map((commit) => ( -
-
- -
-
- - {commit.date.toLocaleTimeString()} - - -
-
- ))} -
-
- ) -} diff --git a/react-change-tracking/src/components/editor/examples/change-tracking/index.ts b/react-change-tracking/src/components/editor/examples/change-tracking/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-change-tracking/src/components/editor/examples/change-tracking/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-change-tracking/src/main.tsx b/react-change-tracking/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-change-tracking/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-change-tracking/tsconfig.app.json b/react-change-tracking/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-change-tracking/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-change-tracking/tsconfig.json b/react-change-tracking/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-change-tracking/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-change-tracking/tsconfig.node.json b/react-change-tracking/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-change-tracking/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-change-tracking/vite.config.ts b/react-change-tracking/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-change-tracking/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-code-block-themes/.gitignore b/react-code-block-themes/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-code-block-themes/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-code-block-themes/README.md b/react-code-block-themes/README.md deleted file mode 100644 index 586ce662fc..0000000000 --- a/react-code-block-themes/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-code-block-themes - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-code-block-themes) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-code-block-themes) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-code-block-themes react-code-block-themes -cd react-code-block-themes -npm install -npm run dev -``` diff --git a/react-code-block-themes/index.html b/react-code-block-themes/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-code-block-themes/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-code-block-themes/package.json b/react-code-block-themes/package.json deleted file mode 100644 index f1440331b1..0000000000 --- a/react-code-block-themes/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-code-block-themes", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-code-block-themes/src/App.tsx b/react-code-block-themes/src/App.tsx deleted file mode 100644 index 9b93464b4e..0000000000 --- a/react-code-block-themes/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code-block-themes' - -export default function App() { - return -} diff --git a/react-code-block-themes/src/app.css b/react-code-block-themes/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-code-block-themes/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx b/react-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx deleted file mode 100644 index fd5a46a903..0000000000 --- a/react-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-code-block' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/react-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts deleted file mode 100644 index b5686b8c04..0000000000 --- a/react-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union(defineBasicExtension(), defineCodeBlockView()) -} - -export type EditorExtension = ReturnType diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/react-code-block-themes/src/components/editor/examples/code-block-themes/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-code-block-themes/src/components/editor/examples/code-block-themes/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx b/react-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx deleted file mode 100644 index 264faf038f..0000000000 --- a/react-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx +++ /dev/null @@ -1,35 +0,0 @@ -'use client' - -import { - defineCodeBlockShiki, - shikiBundledThemesInfo, - type ShikiBundledTheme, -} from 'prosekit/extensions/code-block' -import { useExtension } from 'prosekit/react' -import { useMemo, useState } from 'react' - -export function ThemeSelector() { - const [theme, setTheme] = useState('github-dark') - const extension = useMemo(() => { - return defineCodeBlockShiki({ themes: [theme as ShikiBundledTheme] }) - }, [theme]) - useExtension(extension) - - return ( - <> - - - - ) -} diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx b/react-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx deleted file mode 100644 index 566c98f931..0000000000 --- a/react-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx +++ /dev/null @@ -1,11 +0,0 @@ -'use client' - -import { ThemeSelector } from './theme-selector' - -export default function Toolbar() { - return ( -
- -
- ) -} diff --git a/react-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/react-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/react-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/react-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx b/react-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index f6c0428091..0000000000 --- a/react-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { ReactNodeViewProps } from 'prosekit/react' - -export default function CodeBlockView(props: ReactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/react-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/react-code-block-themes/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index b7e6b996bc..0000000000
--- a/react-code-block-themes/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineReactNodeView,
-  type ReactNodeViewComponent,
-} from 'prosekit/react'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineReactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies ReactNodeViewComponent,
-  })
-}
diff --git a/react-code-block-themes/src/main.tsx b/react-code-block-themes/src/main.tsx
deleted file mode 100644
index 87de8eb52b..0000000000
--- a/react-code-block-themes/src/main.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import './app.css'
-import React from 'react'
-import ReactDOM from 'react-dom/client'
-import App from './App.tsx'
-
-ReactDOM.createRoot(document.getElementById('root')!).render(
-  
-    
-  ,
-)
diff --git a/react-code-block-themes/tsconfig.app.json b/react-code-block-themes/tsconfig.app.json
deleted file mode 100644
index a9b5a59ca6..0000000000
--- a/react-code-block-themes/tsconfig.app.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
-    "target": "ES2022",
-    "useDefineForClassFields": true,
-    "lib": ["ES2022", "DOM", "DOM.Iterable"],
-    "module": "ESNext",
-    "types": ["vite/client"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-    "jsx": "react-jsx",
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["src"]
-}
diff --git a/react-code-block-themes/tsconfig.json b/react-code-block-themes/tsconfig.json
deleted file mode 100644
index 1ffef600d9..0000000000
--- a/react-code-block-themes/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "files": [],
-  "references": [
-    { "path": "./tsconfig.app.json" },
-    { "path": "./tsconfig.node.json" }
-  ]
-}
diff --git a/react-code-block-themes/tsconfig.node.json b/react-code-block-themes/tsconfig.node.json
deleted file mode 100644
index 8a67f62f4c..0000000000
--- a/react-code-block-themes/tsconfig.node.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
-    "target": "ES2023",
-    "lib": ["ES2023"],
-    "module": "ESNext",
-    "types": ["node"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/react-code-block-themes/vite.config.ts b/react-code-block-themes/vite.config.ts
deleted file mode 100644
index c90997597d..0000000000
--- a/react-code-block-themes/vite.config.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
-import tailwindcss from '@tailwindcss/vite'
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  plugins: [react(), tailwindcss()],
-})
diff --git a/react-code-block/.gitignore b/react-code-block/.gitignore
deleted file mode 100644
index 5d6225c6df..0000000000
--- a/react-code-block/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-dist
-.next
-.svelte-kit
diff --git a/react-code-block/README.md b/react-code-block/README.md
deleted file mode 100644
index eee18c3190..0000000000
--- a/react-code-block/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# react-code-block
-
-A [ProseKit](https://prosekit.dev) example.
-
-[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-code-block)
-[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-code-block)
-
-Run the example locally with:
-
-```bash
-npx degit prosekit/examples/react-code-block react-code-block
-cd react-code-block
-npm install
-npm run dev
-```
diff --git a/react-code-block/index.html b/react-code-block/index.html
deleted file mode 100644
index a5a78f3bf8..0000000000
--- a/react-code-block/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-  
-    
-    
-    ProseKit + React
-  
-  
-    
- - - diff --git a/react-code-block/package.json b/react-code-block/package.json deleted file mode 100644 index e09bf534dd..0000000000 --- a/react-code-block/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-code-block", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-code-block/src/App.tsx b/react-code-block/src/App.tsx deleted file mode 100644 index 961ce70aad..0000000000 --- a/react-code-block/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code-block' - -export default function App() { - return -} diff --git a/react-code-block/src/app.css b/react-code-block/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-code-block/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-code-block/src/components/editor/examples/code-block/editor.tsx b/react-code-block/src/components/editor/examples/code-block/editor.tsx deleted file mode 100644 index f241113958..0000000000 --- a/react-code-block/src/components/editor/examples/code-block/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-code-block' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-code-block/src/components/editor/examples/code-block/extension.ts b/react-code-block/src/components/editor/examples/code-block/extension.ts deleted file mode 100644 index 099cacf03b..0000000000 --- a/react-code-block/src/components/editor/examples/code-block/extension.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { - defineCodeBlock, - defineCodeBlockShiki, -} from 'prosekit/extensions/code-block' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCodeBlock(), - defineCodeBlockShiki(), - defineCodeBlockView(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-code-block/src/components/editor/examples/code-block/index.ts b/react-code-block/src/components/editor/examples/code-block/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-code-block/src/components/editor/examples/code-block/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-code-block/src/components/editor/sample/sample-doc-code-block.ts b/react-code-block/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/react-code-block/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/react-code-block/src/components/editor/ui/button/button.tsx b/react-code-block/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-code-block/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-code-block/src/components/editor/ui/button/index.ts b/react-code-block/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-code-block/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx b/react-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index f6c0428091..0000000000 --- a/react-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { ReactNodeViewProps } from 'prosekit/react' - -export default function CodeBlockView(props: ReactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/react-code-block/src/components/editor/ui/code-block-view/index.ts b/react-code-block/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index b7e6b996bc..0000000000
--- a/react-code-block/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineReactNodeView,
-  type ReactNodeViewComponent,
-} from 'prosekit/react'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineReactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies ReactNodeViewComponent,
-  })
-}
diff --git a/react-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
deleted file mode 100644
index 808361b6ad..0000000000
--- a/react-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-'use client'
-
-import type { Uploader } from 'prosekit/extensions/file'
-import type { ImageExtension } from 'prosekit/extensions/image'
-import { useEditor } from 'prosekit/react'
-import {
-  PopoverPopup,
-  PopoverPositioner,
-  PopoverRoot,
-  PopoverTrigger,
-} from 'prosekit/react/popover'
-import type { OpenChangeEvent } from 'prosekit/web/popover'
-import { useId, useState, type ReactNode } from 'react'
-
-import { Button } from '../button'
-
-export default function ImageUploadPopover(props: {
-  uploader: Uploader
-  tooltip: string
-  disabled: boolean
-  children: ReactNode
-}) {
-  const [open, setOpen] = useState(false)
-  const [url, setUrl] = useState('')
-  const [file, setFile] = useState(null)
-  const ariaId = useId()
-
-  const editor = useEditor()
-
-  const handleFileChange: React.ChangeEventHandler = (
-    event,
-  ) => {
-    const file = event.target.files?.[0]
-
-    if (file) {
-      setFile(file)
-      setUrl('')
-    } else {
-      setFile(null)
-    }
-  }
-
-  const handleUrlChange: React.ChangeEventHandler = (
-    event,
-  ) => {
-    const url = event.target.value
-
-    if (url) {
-      setUrl(url)
-      setFile(null)
-    } else {
-      setUrl('')
-    }
-  }
-
-  const deferResetState = () => {
-    setTimeout(() => {
-      setUrl('')
-      setFile(null)
-    }, 300)
-  }
-
-  const handleSubmit = () => {
-    if (url) {
-      editor.commands.insertImage({ src: url })
-    } else if (file) {
-      editor.commands.uploadImage({ file, uploader: props.uploader })
-    }
-    setOpen(false)
-    deferResetState()
-  }
-
-  const handleOpenChange = (event: OpenChangeEvent) => {
-    if (!event.detail) {
-      deferResetState()
-    }
-    setOpen(event.detail)
-  }
-
-  return (
-    
-      
-        
-      
-
-      
-        
-          {file ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? (
-            
-          ) : null}
-
-          {file ? (
-            
-          ) : null}
-        
-      
-    
-  )
-}
diff --git a/react-code-block/src/components/editor/ui/image-upload-popover/index.ts b/react-code-block/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index 5d49d873ce..0000000000
--- a/react-code-block/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/react-code-block/src/components/editor/ui/toolbar/index.ts b/react-code-block/src/components/editor/ui/toolbar/index.ts
deleted file mode 100644
index fdf6741e6a..0000000000
--- a/react-code-block/src/components/editor/ui/toolbar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as Toolbar } from './toolbar'
diff --git a/react-code-block/src/components/editor/ui/toolbar/toolbar.tsx b/react-code-block/src/components/editor/ui/toolbar/toolbar.tsx
deleted file mode 100644
index ce61a2d041..0000000000
--- a/react-code-block/src/components/editor/ui/toolbar/toolbar.tsx
+++ /dev/null
@@ -1,365 +0,0 @@
-'use client'
-
-import type { BasicExtension } from 'prosekit/basic'
-import type { Editor } from 'prosekit/core'
-import type { Uploader } from 'prosekit/extensions/file'
-import { useEditorDerivedValue } from 'prosekit/react'
-
-import { Button } from '../button'
-import { ImageUploadPopover } from '../image-upload-popover'
-
-function getToolbarItems(editor: Editor) {
-  return {
-    undo: editor.commands.undo
-      ? {
-          isActive: false,
-          canExec: editor.commands.undo.canExec(),
-          command: () => editor.commands.undo(),
-        }
-      : undefined,
-    redo: editor.commands.redo
-      ? {
-          isActive: false,
-          canExec: editor.commands.redo.canExec(),
-          command: () => editor.commands.redo(),
-        }
-      : undefined,
-    bold: editor.commands.toggleBold
-      ? {
-          isActive: editor.marks.bold.isActive(),
-          canExec: editor.commands.toggleBold.canExec(),
-          command: () => editor.commands.toggleBold(),
-        }
-      : undefined,
-    italic: editor.commands.toggleItalic
-      ? {
-          isActive: editor.marks.italic.isActive(),
-          canExec: editor.commands.toggleItalic.canExec(),
-          command: () => editor.commands.toggleItalic(),
-        }
-      : undefined,
-    underline: editor.commands.toggleUnderline
-      ? {
-          isActive: editor.marks.underline.isActive(),
-          canExec: editor.commands.toggleUnderline.canExec(),
-          command: () => editor.commands.toggleUnderline(),
-        }
-      : undefined,
-    strike: editor.commands.toggleStrike
-      ? {
-          isActive: editor.marks.strike.isActive(),
-          canExec: editor.commands.toggleStrike.canExec(),
-          command: () => editor.commands.toggleStrike(),
-        }
-      : undefined,
-    code: editor.commands.toggleCode
-      ? {
-          isActive: editor.marks.code.isActive(),
-          canExec: editor.commands.toggleCode.canExec(),
-          command: () => editor.commands.toggleCode(),
-        }
-      : undefined,
-    codeBlock: editor.commands.insertCodeBlock
-      ? {
-          isActive: editor.nodes.codeBlock.isActive(),
-          canExec: editor.commands.insertCodeBlock.canExec({
-            language: 'javascript',
-          }),
-          command: () =>
-            editor.commands.insertCodeBlock({ language: 'javascript' }),
-        }
-      : undefined,
-    heading1: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 1 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 1 }),
-          command: () => editor.commands.toggleHeading({ level: 1 }),
-        }
-      : undefined,
-    heading2: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 2 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 2 }),
-          command: () => editor.commands.toggleHeading({ level: 2 }),
-        }
-      : undefined,
-    heading3: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 3 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 3 }),
-          command: () => editor.commands.toggleHeading({ level: 3 }),
-        }
-      : undefined,
-    horizontalRule: editor.commands.insertHorizontalRule
-      ? {
-          isActive: editor.nodes.horizontalRule.isActive(),
-          canExec: editor.commands.insertHorizontalRule.canExec(),
-          command: () => editor.commands.insertHorizontalRule(),
-        }
-      : undefined,
-    blockquote: editor.commands.toggleBlockquote
-      ? {
-          isActive: editor.nodes.blockquote.isActive(),
-          canExec: editor.commands.toggleBlockquote.canExec(),
-          command: () => editor.commands.toggleBlockquote(),
-        }
-      : undefined,
-    bulletList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'bullet' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }),
-          command: () => editor.commands.toggleList({ kind: 'bullet' }),
-        }
-      : undefined,
-    orderedList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'ordered' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }),
-          command: () => editor.commands.toggleList({ kind: 'ordered' }),
-        }
-      : undefined,
-    taskList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'task' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'task' }),
-          command: () => editor.commands.toggleList({ kind: 'task' }),
-        }
-      : undefined,
-    toggleList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'toggle' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }),
-          command: () => editor.commands.toggleList({ kind: 'toggle' }),
-        }
-      : undefined,
-    indentList: editor.commands.indentList
-      ? {
-          isActive: false,
-          canExec: editor.commands.indentList.canExec(),
-          command: () => editor.commands.indentList(),
-        }
-      : undefined,
-    dedentList: editor.commands.dedentList
-      ? {
-          isActive: false,
-          canExec: editor.commands.dedentList.canExec(),
-          command: () => editor.commands.dedentList(),
-        }
-      : undefined,
-    insertImage: editor.commands.insertImage
-      ? {
-          isActive: false,
-          canExec: editor.commands.insertImage.canExec(),
-        }
-      : undefined,
-  }
-}
-
-export default function Toolbar(props: { uploader?: Uploader }) {
-  const items = useEditorDerivedValue(getToolbarItems)
-
-  return (
-    
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-code-block/src/main.tsx b/react-code-block/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-code-block/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-code-block/tsconfig.app.json b/react-code-block/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-code-block/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-code-block/tsconfig.json b/react-code-block/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-code-block/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-code-block/tsconfig.node.json b/react-code-block/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-code-block/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-code-block/vite.config.ts b/react-code-block/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-code-block/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-code/.gitignore b/react-code/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-code/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-code/README.md b/react-code/README.md deleted file mode 100644 index a07555ea9e..0000000000 --- a/react-code/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-code - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-code) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-code) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-code react-code -cd react-code -npm install -npm run dev -``` diff --git a/react-code/index.html b/react-code/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-code/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-code/package.json b/react-code/package.json deleted file mode 100644 index 93c51d42b9..0000000000 --- a/react-code/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-code", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-code/src/App.tsx b/react-code/src/App.tsx deleted file mode 100644 index f2f5d9a360..0000000000 --- a/react-code/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code' - -export default function App() { - return -} diff --git a/react-code/src/app.css b/react-code/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-code/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-code/src/components/editor/examples/code/editor.tsx b/react-code/src/components/editor/examples/code/editor.tsx deleted file mode 100644 index bef4c5dab0..0000000000 --- a/react-code/src/components/editor/examples/code/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-code' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-code/src/components/editor/examples/code/extension.ts b/react-code/src/components/editor/examples/code/extension.ts deleted file mode 100644 index e9e273216e..0000000000 --- a/react-code/src/components/editor/examples/code/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCode(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-code/src/components/editor/examples/code/index.ts b/react-code/src/components/editor/examples/code/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-code/src/components/editor/examples/code/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-code/src/components/editor/sample/sample-doc-code.ts b/react-code/src/components/editor/sample/sample-doc-code.ts deleted file mode 100644 index 2fdbcee1f3..0000000000 --- a/react-code/src/components/editor/sample/sample-doc-code.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'This is code', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/react-code/src/components/editor/ui/button/button.tsx b/react-code/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-code/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-code/src/components/editor/ui/button/index.ts b/react-code/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-code/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-code/src/components/editor/ui/image-upload-popover/index.ts b/react-code/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-code/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-code/src/components/editor/ui/toolbar/index.ts b/react-code/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-code/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-code/src/components/editor/ui/toolbar/toolbar.tsx b/react-code/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-code/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-code/src/main.tsx b/react-code/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-code/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-code/tsconfig.app.json b/react-code/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-code/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-code/tsconfig.json b/react-code/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-code/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-code/tsconfig.node.json b/react-code/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-code/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-code/vite.config.ts b/react-code/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-code/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-drop-cursor/.gitignore b/react-drop-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-drop-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-drop-cursor/README.md b/react-drop-cursor/README.md deleted file mode 100644 index c42e139f4c..0000000000 --- a/react-drop-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-drop-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-drop-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-drop-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-drop-cursor react-drop-cursor -cd react-drop-cursor -npm install -npm run dev -``` diff --git a/react-drop-cursor/index.html b/react-drop-cursor/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-drop-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-drop-cursor/package.json b/react-drop-cursor/package.json deleted file mode 100644 index b37927d1a1..0000000000 --- a/react-drop-cursor/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-drop-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-drop-cursor/src/App.tsx b/react-drop-cursor/src/App.tsx deleted file mode 100644 index f66459b286..0000000000 --- a/react-drop-cursor/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/drop-cursor' - -export default function App() { - return -} diff --git a/react-drop-cursor/src/app.css b/react-drop-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-drop-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx b/react-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx deleted file mode 100644 index 8dedc17ac0..0000000000 --- a/react-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-drop-cursor' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/react-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts deleted file mode 100644 index fd79a2c96c..0000000000 --- a/react-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineImage(), - defineDropCursor({ - color: false, - width: 4, - class: 'transition-all bg-blue-500', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/react-drop-cursor/src/components/editor/examples/drop-cursor/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-drop-cursor/src/components/editor/examples/drop-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/react-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts deleted file mode 100644 index 22c6b93465..0000000000 --- a/react-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the images below to see the custom drop cursor.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/320x240/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/green/320x240/40', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blue/320x240/187', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/red/320x240/188', - }, - }, - ], -} diff --git a/react-drop-cursor/src/main.tsx b/react-drop-cursor/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-drop-cursor/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-drop-cursor/tsconfig.app.json b/react-drop-cursor/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-drop-cursor/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-drop-cursor/tsconfig.json b/react-drop-cursor/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-drop-cursor/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-drop-cursor/tsconfig.node.json b/react-drop-cursor/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-drop-cursor/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-drop-cursor/vite.config.ts b/react-drop-cursor/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-drop-cursor/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-emoji-rules/.gitignore b/react-emoji-rules/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-emoji-rules/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-emoji-rules/README.md b/react-emoji-rules/README.md deleted file mode 100644 index 5a602af6b1..0000000000 --- a/react-emoji-rules/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-emoji-rules - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-emoji-rules) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-emoji-rules) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-emoji-rules react-emoji-rules -cd react-emoji-rules -npm install -npm run dev -``` diff --git a/react-emoji-rules/index.html b/react-emoji-rules/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-emoji-rules/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-emoji-rules/package.json b/react-emoji-rules/package.json deleted file mode 100644 index 93e259cdab..0000000000 --- a/react-emoji-rules/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-emoji-rules", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-emoji-rules/src/App.tsx b/react-emoji-rules/src/App.tsx deleted file mode 100644 index 1e4ef54fd6..0000000000 --- a/react-emoji-rules/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/emoji-rules' - -export default function App() { - return -} diff --git a/react-emoji-rules/src/app.css b/react-emoji-rules/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-emoji-rules/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx b/react-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx deleted file mode 100644 index c17d11fd22..0000000000 --- a/react-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx +++ /dev/null @@ -1,30 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/react-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts deleted file mode 100644 index 5cac9cbc79..0000000000 --- a/react-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineEnterRule } from 'prosekit/extensions/enter-rule' - -/** - * Converts the text before the text cursor into an emoji when pressing `Enter`. - */ -export function defineEmojiEnterRule() { - return defineEnterRule({ - regex: /:(apple|banana):$/, - handler: ({ match, from, to, state }) => { - const text = match[1] as 'apple' | 'banana' - const emoji = text === 'apple' ? '🍎' : '🍌' - return state.tr.replaceWith(from, to, state.schema.text(emoji)) - }, - }) -} diff --git a/react-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/react-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts deleted file mode 100644 index bc9bcb8412..0000000000 --- a/react-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { defineEmojiEnterRule } from './emoji' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineEmojiEnterRule(), - definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/react-emoji-rules/src/components/editor/examples/emoji-rules/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-emoji-rules/src/components/editor/examples/emoji-rules/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-emoji-rules/src/main.tsx b/react-emoji-rules/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-emoji-rules/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-emoji-rules/tsconfig.app.json b/react-emoji-rules/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-emoji-rules/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-emoji-rules/tsconfig.json b/react-emoji-rules/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-emoji-rules/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-emoji-rules/tsconfig.node.json b/react-emoji-rules/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-emoji-rules/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-emoji-rules/vite.config.ts b/react-emoji-rules/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-emoji-rules/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-full/.gitignore b/react-full/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-full/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-full/README.md b/react-full/README.md deleted file mode 100644 index cbe69d8c6e..0000000000 --- a/react-full/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-full - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-full) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-full) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-full react-full -cd react-full -npm install -npm run dev -``` diff --git a/react-full/index.html b/react-full/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-full/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-full/package.json b/react-full/package.json deleted file mode 100644 index a083c17177..0000000000 --- a/react-full/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-react-full", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-full/src/App.tsx b/react-full/src/App.tsx deleted file mode 100644 index c93bd3a429..0000000000 --- a/react-full/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/full' - -export default function App() { - return -} diff --git a/react-full/src/app.css b/react-full/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-full/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-full/src/components/editor/examples/full/editor.tsx b/react-full/src/components/editor/examples/full/editor.tsx deleted file mode 100644 index d49fac1be9..0000000000 --- a/react-full/src/components/editor/examples/full/editor.tsx +++ /dev/null @@ -1,56 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-full' -import { tags } from '../../sample/sample-tag-data' -import { sampleUploader } from '../../sample/sample-uploader' -import { users } from '../../sample/sample-user-data' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' -import { InlineMenu } from '../../ui/inline-menu' -import { SlashMenu } from '../../ui/slash-menu' -import { TableHandle } from '../../ui/table-handle' -import { TagMenu } from '../../ui/tag-menu' -import { Toolbar } from '../../ui/toolbar' -import { UserMenu } from '../../ui/user-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
- - - - - - - -
-
-
- ) -} diff --git a/react-full/src/components/editor/examples/full/extension.ts b/react-full/src/components/editor/examples/full/extension.ts deleted file mode 100644 index 5fc2f60685..0000000000 --- a/react-full/src/components/editor/examples/full/extension.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineImageUploadHandler } from 'prosekit/extensions/image' -import { defineMath } from 'prosekit/extensions/math' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' -import { sampleUploader } from '../../sample/sample-uploader' -import { defineCodeBlockView } from '../../ui/code-block-view' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - defineMention(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - defineCodeBlockShiki(), - defineHorizontalRule(), - defineCodeBlockView(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-full/src/components/editor/examples/full/html.ts b/react-full/src/components/editor/examples/full/html.ts deleted file mode 100644 index 4945ec9108..0000000000 --- a/react-full/src/components/editor/examples/full/html.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { createEditor, type NodeJSON } from 'prosekit/core' - -import { sampleContent } from '../../sample/sample-doc-full' - -import { defineExtension } from './extension' - -/** - * Renders a ProseMirror document JSON object to an HTML string. - * - * This is useful for server-side rendering. - * - * @example - * - * ```js - * import { JSDOM } from 'jsdom' - * const dom = new JSDOM('') - * const document = dom.window.document - * const html = renderHTML(document, myContentJSON) - * ``` - */ -export function renderHTML( - document: Document, - content: NodeJSON = sampleContent, -): string { - const extension = defineExtension() - const editor = createEditor({ extension }) - editor.setContent(content) - const html: string = editor.getDocHTML({ document }) - if (html.startsWith('
') && html.endsWith('
')) { - return html.slice(5, -6) // Remove the wrapping
tags - } else { - console.error('Unexpected HTML format: expected a single
wrapper') - return html - } -} diff --git a/react-full/src/components/editor/examples/full/index.ts b/react-full/src/components/editor/examples/full/index.ts deleted file mode 100644 index 516b54a1f0..0000000000 --- a/react-full/src/components/editor/examples/full/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as ExampleEditor } from './editor' -export { renderHTML } from './html' diff --git a/react-full/src/components/editor/sample/katex.ts b/react-full/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/react-full/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/react-full/src/components/editor/sample/sample-doc-full.ts b/react-full/src/components/editor/sample/sample-doc-full.ts deleted file mode 100644 index 13e49b634d..0000000000 --- a/react-full/src/components/editor/sample/sample-doc-full.ts +++ /dev/null @@ -1,442 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'The editor that thinks like you' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', - }, - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'writing without barriers', - }, - { type: 'text', text: '.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Text that shines.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Make your words ' }, - { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, - { type: 'text', text: ', or ' }, - { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, - { type: 'text', text: '. Add ' }, - { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, - { type: 'text', text: ' that stands out. Create ' }, - { - type: 'text', - marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], - text: 'links', - }, - { type: 'text', text: ' that connect.' }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Select any text to format it. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '@' }, - { type: 'text', text: ' to mention ' }, - { - type: 'mention', - attrs: { id: '39', value: '@someone', kind: 'user' }, - }, - { type: 'text', text: ' or ' }, - { type: 'text', marks: [{ type: 'code' }], text: '#' }, - { type: 'text', text: ' for ' }, - { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, - { type: 'text', text: '. Press ' }, - { type: 'text', marks: [{ type: 'code' }], text: '/' }, - { type: 'text', text: " and discover what's possible." }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Lists that organize.' }], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Bullet points that guide thoughts' }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Nested lists for complex ideas' }], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sub-points flow naturally' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Tasks that focus' }], - }, - { - type: 'list', - attrs: { kind: 'task', order: null, checked: true, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Done feels good' }], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Todo drives action' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Numbered steps' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sequential thinking' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Clear progress' }], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Code that inspires.' }], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Images that captivate.' }], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/season/320x240/107', - }, - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the handle in the bottom right corner to resize.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Tables that structure.' }], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'Feature', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'How to use', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Format text' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Select and choose' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Perfect styling' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Add mentions' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Type @ and name' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Connected ideas' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Insert anything' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Press / for menu' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Endless possibilities' }], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Math that renders.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Inline math like ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' appears within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Quotes that inspire.' }], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: '"This is not just an editor. This is how writing should feel."', - }, - ], - }, - ], - }, - { type: 'horizontalRule' }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Start typing. Everything else just flows.' }, - ], - }, - ], -} diff --git a/react-full/src/components/editor/sample/sample-tag-data.ts b/react-full/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/react-full/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/react-full/src/components/editor/sample/sample-uploader.ts b/react-full/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/react-full/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/react-full/src/components/editor/sample/sample-user-data.ts b/react-full/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/react-full/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/react-full/src/components/editor/ui/block-handle/block-handle.tsx b/react-full/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 3cc6028d5c..0000000000 --- a/react-full/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' - -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/react/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/react-full/src/components/editor/ui/block-handle/index.ts b/react-full/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/react-full/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/react-full/src/components/editor/ui/button/button.tsx b/react-full/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-full/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-full/src/components/editor/ui/button/index.ts b/react-full/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-full/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-full/src/components/editor/ui/code-block-view/code-block-view.tsx b/react-full/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index f6c0428091..0000000000 --- a/react-full/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { ReactNodeViewProps } from 'prosekit/react' - -export default function CodeBlockView(props: ReactNodeViewProps) { - const attrs = props.node.attrs as CodeBlockAttrs - const language = attrs.language - - const setLanguage = (language: string) => { - const attrs: CodeBlockAttrs = { language } - props.setAttrs(attrs) - } - - return ( - <> -
- -
-

-    
-  )
-}
diff --git a/react-full/src/components/editor/ui/code-block-view/index.ts b/react-full/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index b7e6b996bc..0000000000
--- a/react-full/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineReactNodeView,
-  type ReactNodeViewComponent,
-} from 'prosekit/react'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineReactNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies ReactNodeViewComponent,
-  })
-}
diff --git a/react-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/react-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
deleted file mode 100644
index 87c1746622..0000000000
--- a/react-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-'use client'
-
-import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator'
-
-export default function DropIndicator() {
-  return 
-}
diff --git a/react-full/src/components/editor/ui/drop-indicator/index.ts b/react-full/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index f8fb7139c4..0000000000
--- a/react-full/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator'
diff --git a/react-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
deleted file mode 100644
index 808361b6ad..0000000000
--- a/react-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
+++ /dev/null
@@ -1,145 +0,0 @@
-'use client'
-
-import type { Uploader } from 'prosekit/extensions/file'
-import type { ImageExtension } from 'prosekit/extensions/image'
-import { useEditor } from 'prosekit/react'
-import {
-  PopoverPopup,
-  PopoverPositioner,
-  PopoverRoot,
-  PopoverTrigger,
-} from 'prosekit/react/popover'
-import type { OpenChangeEvent } from 'prosekit/web/popover'
-import { useId, useState, type ReactNode } from 'react'
-
-import { Button } from '../button'
-
-export default function ImageUploadPopover(props: {
-  uploader: Uploader
-  tooltip: string
-  disabled: boolean
-  children: ReactNode
-}) {
-  const [open, setOpen] = useState(false)
-  const [url, setUrl] = useState('')
-  const [file, setFile] = useState(null)
-  const ariaId = useId()
-
-  const editor = useEditor()
-
-  const handleFileChange: React.ChangeEventHandler = (
-    event,
-  ) => {
-    const file = event.target.files?.[0]
-
-    if (file) {
-      setFile(file)
-      setUrl('')
-    } else {
-      setFile(null)
-    }
-  }
-
-  const handleUrlChange: React.ChangeEventHandler = (
-    event,
-  ) => {
-    const url = event.target.value
-
-    if (url) {
-      setUrl(url)
-      setFile(null)
-    } else {
-      setUrl('')
-    }
-  }
-
-  const deferResetState = () => {
-    setTimeout(() => {
-      setUrl('')
-      setFile(null)
-    }, 300)
-  }
-
-  const handleSubmit = () => {
-    if (url) {
-      editor.commands.insertImage({ src: url })
-    } else if (file) {
-      editor.commands.uploadImage({ file, uploader: props.uploader })
-    }
-    setOpen(false)
-    deferResetState()
-  }
-
-  const handleOpenChange = (event: OpenChangeEvent) => {
-    if (!event.detail) {
-      deferResetState()
-    }
-    setOpen(event.detail)
-  }
-
-  return (
-    
-      
-        
-      
-
-      
-        
-          {file ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? null : (
-            <>
-              
-              
-            
-          )}
-
-          {url ? (
-            
-          ) : null}
-
-          {file ? (
-            
-          ) : null}
-        
-      
-    
-  )
-}
diff --git a/react-full/src/components/editor/ui/image-upload-popover/index.ts b/react-full/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index 5d49d873ce..0000000000
--- a/react-full/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/react-full/src/components/editor/ui/image-view/image-view.tsx b/react-full/src/components/editor/ui/image-view/image-view.tsx
deleted file mode 100644
index 06da475774..0000000000
--- a/react-full/src/components/editor/ui/image-view/image-view.tsx
+++ /dev/null
@@ -1,94 +0,0 @@
-'use client'
-
-import { UploadTask } from 'prosekit/extensions/file'
-import type { ImageAttrs } from 'prosekit/extensions/image'
-import type { ReactNodeViewProps } from 'prosekit/react'
-import { ResizableHandle, ResizableRoot } from 'prosekit/react/resizable'
-import { useEffect, useState, type SyntheticEvent } from 'react'
-
-export default function ImageView(props: ReactNodeViewProps) {
-  const attrs = props.node.attrs as ImageAttrs
-  const url = attrs.src || ''
-  const uploading = url.startsWith('blob:')
-
-  const [aspectRatio, setAspectRatio] = useState()
-  const [error, setError] = useState()
-  const [progress, setProgress] = useState(0)
-
-  useEffect(() => {
-    if (!uploading) return
-
-    const uploadTask = UploadTask.get(url)
-    if (!uploadTask) return
-
-    let canceled = false
-
-    uploadTask.finished.catch((error) => {
-      if (canceled) return
-      setError(String(error))
-    })
-    const unsubscribeProgress = uploadTask.subscribeProgress(
-      ({ loaded, total }) => {
-        if (canceled) return
-        setProgress(total ? loaded / total : 0)
-      },
-    )
-
-    return () => {
-      canceled = true
-      unsubscribeProgress()
-    }
-  }, [url, uploading])
-
-  const handleImageLoad = (event: SyntheticEvent) => {
-    const img = event.target as HTMLImageElement
-    const { naturalWidth, naturalHeight } = img
-    const ratio = naturalWidth / naturalHeight
-    if (ratio && Number.isFinite(ratio)) {
-      setAspectRatio(ratio)
-    }
-    if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) {
-      props.setAttrs({ width: naturalWidth, height: naturalHeight })
-    }
-  }
-
-  return (
-     props.setAttrs(event.detail)}
-      data-selected={props.selected ? '' : undefined}
-      className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid"
-    >
-      {url && !error && (
-        upload preview
-      )}
-      {uploading && !error && (
-        
-
-
{Math.round(progress * 100)}%
-
- )} - {error && ( -
-
-
- Failed to upload image -
-
- )} - -
-
-
- ) -} diff --git a/react-full/src/components/editor/ui/image-view/index.ts b/react-full/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index c4a95f9d3f..0000000000 --- a/react-full/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - defineReactNodeView, - type ReactNodeViewComponent, -} from 'prosekit/react' - -import ImageView from './image-view' - -export function defineImageView(): Extension { - return defineReactNodeView({ - name: 'image', - component: ImageView satisfies ReactNodeViewComponent, - }) -} diff --git a/react-full/src/components/editor/ui/inline-menu/index.ts b/react-full/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/react-full/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/react-full/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-full/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index af1b2bb2b7..0000000000 --- a/react-full/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/react' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/react/inline-popover' -import { useState } from 'react' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/react-full/src/components/editor/ui/slash-menu/index.ts b/react-full/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/react-full/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/react-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/react-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index d0dca0934a..0000000000 --- a/react-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,11 +0,0 @@ -'use client' - -import { AutocompleteEmpty } from 'prosekit/react/autocomplete' - -export default function SlashMenuEmpty() { - return ( - - No results - - ) -} diff --git a/react-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/react-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 349c6e8924..0000000000 --- a/react-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client' - -import { AutocompleteItem } from 'prosekit/react/autocomplete' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}) { - return ( - - {props.label} - {props.kbd && ( - - {props.kbd} - - )} - - ) -} diff --git a/react-full/src/components/editor/ui/slash-menu/slash-menu.tsx b/react-full/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index 3738f51aab..0000000000 --- a/react-full/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,102 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/react' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor.commands.setParagraph()} - /> - - editor.commands.setHeading({ level: 1 })} - /> - - editor.commands.setHeading({ level: 2 })} - /> - - editor.commands.setHeading({ level: 3 })} - /> - - editor.commands.wrapInList({ kind: 'bullet' })} - /> - - editor.commands.wrapInList({ kind: 'ordered' })} - /> - - editor.commands.wrapInList({ kind: 'task' })} - /> - - editor.commands.wrapInList({ kind: 'toggle' })} - /> - - editor.commands.setBlockquote()} - /> - - editor.commands.insertTable({ row: 3, col: 3 })} - /> - - editor.commands.insertHorizontalRule()} - /> - - editor.commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/react-full/src/components/editor/ui/table-handle/index.ts b/react-full/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/react-full/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/react-full/src/components/editor/ui/table-handle/table-handle.tsx b/react-full/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index b90b351382..0000000000 --- a/react-full/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,188 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/react' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/react/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/react/table-handle' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props) { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - {state.addTableColumnBefore.canExec && ( - - Insert Left - - )} - {state.addTableColumnAfter.canExec && ( - - Insert Right - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableColumn.canExec && ( - - Delete Column - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
- - - - -
-
- - - {state.addTableRowAbove.canExec && ( - - Insert Above - - )} - {state.addTableRowBelow.canExec && ( - - Insert Below - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableRow.canExec && ( - - Delete Row - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
-
- ) -} diff --git a/react-full/src/components/editor/ui/tag-menu/index.ts b/react-full/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index d344b33a70..0000000000 --- a/react-full/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu' diff --git a/react-full/src/components/editor/ui/tag-menu/tag-menu.tsx b/react-full/src/components/editor/ui/tag-menu/tag-menu.tsx deleted file mode 100644 index 711486fcf7..0000000000 --- a/react-full/src/components/editor/ui/tag-menu/tag-menu.tsx +++ /dev/null @@ -1,54 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/react' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -const regex = /#[\da-z]*$/i - -export default function TagMenu(props: { - tags: { id: number; label: string }[] -}) { - const editor = useEditor>() - - const handleTagInsert = (id: number, label: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '#' + label, - kind: 'tag', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - - - -
- - No results - - - {props.tags.map((tag) => ( - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - ))} -
-
-
-
- ) -} diff --git a/react-full/src/components/editor/ui/toolbar/index.ts b/react-full/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-full/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-full/src/components/editor/ui/toolbar/toolbar.tsx b/react-full/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-full/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-full/src/components/editor/ui/user-menu/index.ts b/react-full/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/react-full/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/react-full/src/components/editor/ui/user-menu/user-menu.tsx b/react-full/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 46555f6382..0000000000 --- a/react-full/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,64 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/react' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}) { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - {props.users.map((user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - ))} -
-
-
-
- ) -} diff --git a/react-full/src/main.tsx b/react-full/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-full/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-full/tsconfig.app.json b/react-full/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-full/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-full/tsconfig.json b/react-full/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-full/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-full/tsconfig.node.json b/react-full/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-full/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-full/vite.config.ts b/react-full/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-full/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-gap-cursor/.gitignore b/react-gap-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-gap-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-gap-cursor/README.md b/react-gap-cursor/README.md deleted file mode 100644 index 5e1f3e1da1..0000000000 --- a/react-gap-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-gap-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-gap-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-gap-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-gap-cursor react-gap-cursor -cd react-gap-cursor -npm install -npm run dev -``` diff --git a/react-gap-cursor/index.html b/react-gap-cursor/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-gap-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-gap-cursor/package.json b/react-gap-cursor/package.json deleted file mode 100644 index 8a75ab110b..0000000000 --- a/react-gap-cursor/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-gap-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-gap-cursor/src/App.tsx b/react-gap-cursor/src/App.tsx deleted file mode 100644 index ed7e74417e..0000000000 --- a/react-gap-cursor/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/gap-cursor' - -export default function App() { - return -} diff --git a/react-gap-cursor/src/app.css b/react-gap-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-gap-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx b/react-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx deleted file mode 100644 index 9b852f4ad5..0000000000 --- a/react-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx +++ /dev/null @@ -1,36 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-gap-cursor' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - return createEditor({ extension: defineExtension(), defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/react-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts deleted file mode 100644 index 599497170d..0000000000 --- a/react-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineGapCursor(), - defineImage(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/react-gap-cursor/src/components/editor/examples/gap-cursor/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-gap-cursor/src/components/editor/examples/gap-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/react-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts deleted file mode 100644 index e40ee2a83b..0000000000 --- a/react-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - ], -} diff --git a/react-gap-cursor/src/main.tsx b/react-gap-cursor/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-gap-cursor/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-gap-cursor/tsconfig.app.json b/react-gap-cursor/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-gap-cursor/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-gap-cursor/tsconfig.json b/react-gap-cursor/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-gap-cursor/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-gap-cursor/tsconfig.node.json b/react-gap-cursor/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-gap-cursor/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-gap-cursor/vite.config.ts b/react-gap-cursor/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-gap-cursor/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-hard-break/.gitignore b/react-hard-break/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-hard-break/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-hard-break/README.md b/react-hard-break/README.md deleted file mode 100644 index 551adf5370..0000000000 --- a/react-hard-break/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-hard-break - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-hard-break) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-hard-break) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-hard-break react-hard-break -cd react-hard-break -npm install -npm run dev -``` diff --git a/react-hard-break/index.html b/react-hard-break/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-hard-break/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-hard-break/package.json b/react-hard-break/package.json deleted file mode 100644 index 6cfba6d0b1..0000000000 --- a/react-hard-break/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-hard-break", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-hard-break/src/App.tsx b/react-hard-break/src/App.tsx deleted file mode 100644 index db3ea90c2a..0000000000 --- a/react-hard-break/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/hard-break' - -export default function App() { - return -} diff --git a/react-hard-break/src/app.css b/react-hard-break/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-hard-break/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-hard-break/src/components/editor/examples/hard-break/editor.tsx b/react-hard-break/src/components/editor/examples/hard-break/editor.tsx deleted file mode 100644 index 62f3f272c1..0000000000 --- a/react-hard-break/src/components/editor/examples/hard-break/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-hard-break' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-hard-break/src/components/editor/examples/hard-break/extension.ts b/react-hard-break/src/components/editor/examples/hard-break/extension.ts deleted file mode 100644 index cad2881056..0000000000 --- a/react-hard-break/src/components/editor/examples/hard-break/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHardBreak } from 'prosekit/extensions/hard-break' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHardBreak(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-hard-break/src/components/editor/examples/hard-break/index.ts b/react-hard-break/src/components/editor/examples/hard-break/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-hard-break/src/components/editor/examples/hard-break/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-hard-break/src/components/editor/examples/hard-break/toolbar.tsx b/react-hard-break/src/components/editor/examples/hard-break/toolbar.tsx deleted file mode 100644 index 784e685064..0000000000 --- a/react-hard-break/src/components/editor/examples/hard-break/toolbar.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - hardBreak: { - canExec: editor.commands.insertHardBreak.canExec(), - command: () => editor.commands.insertHardBreak(), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/react-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/react-hard-break/src/components/editor/sample/sample-doc-hard-break.ts deleted file mode 100644 index e1c9786b72..0000000000 --- a/react-hard-break/src/components/editor/sample/sample-doc-hard-break.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: "O'er all the hilltops", - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Is quiet now,', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'In all the treetops', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hearest thou', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hardly a breath;', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'The birds are asleep in the trees:', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Wait, soon like these', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Thou too shalt rest.', - }, - { - type: 'hardBreak', - }, - ], - }, - ], -} diff --git a/react-hard-break/src/components/editor/ui/button/button.tsx b/react-hard-break/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-hard-break/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-hard-break/src/components/editor/ui/button/index.ts b/react-hard-break/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-hard-break/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-hard-break/src/main.tsx b/react-hard-break/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-hard-break/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-hard-break/tsconfig.app.json b/react-hard-break/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-hard-break/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-hard-break/tsconfig.json b/react-hard-break/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-hard-break/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-hard-break/tsconfig.node.json b/react-hard-break/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-hard-break/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-hard-break/vite.config.ts b/react-hard-break/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-hard-break/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-heading/.gitignore b/react-heading/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-heading/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-heading/README.md b/react-heading/README.md deleted file mode 100644 index 0d3635b951..0000000000 --- a/react-heading/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-heading - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-heading) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-heading) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-heading react-heading -cd react-heading -npm install -npm run dev -``` diff --git a/react-heading/index.html b/react-heading/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-heading/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-heading/package.json b/react-heading/package.json deleted file mode 100644 index 601ac32532..0000000000 --- a/react-heading/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-heading", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-heading/src/App.tsx b/react-heading/src/App.tsx deleted file mode 100644 index c70e72d05f..0000000000 --- a/react-heading/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/heading' - -export default function App() { - return -} diff --git a/react-heading/src/app.css b/react-heading/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-heading/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-heading/src/components/editor/examples/heading/editor.tsx b/react-heading/src/components/editor/examples/heading/editor.tsx deleted file mode 100644 index e1d392e168..0000000000 --- a/react-heading/src/components/editor/examples/heading/editor.tsx +++ /dev/null @@ -1,38 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-heading' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - return createEditor({ extension: defineExtension(), defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-heading/src/components/editor/examples/heading/extension.ts b/react-heading/src/components/editor/examples/heading/extension.ts deleted file mode 100644 index e4f8e6ace0..0000000000 --- a/react-heading/src/components/editor/examples/heading/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHeading(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-heading/src/components/editor/examples/heading/index.ts b/react-heading/src/components/editor/examples/heading/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-heading/src/components/editor/examples/heading/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-heading/src/components/editor/sample/sample-doc-heading.ts b/react-heading/src/components/editor/sample/sample-doc-heading.ts deleted file mode 100644 index 210497e633..0000000000 --- a/react-heading/src/components/editor/sample/sample-doc-heading.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'H1' }], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'H2' }], - }, - { - type: 'heading', - attrs: { level: 3 }, - content: [{ type: 'text', text: 'H3' }], - }, - { type: 'paragraph', content: [] }, - ], -} diff --git a/react-heading/src/components/editor/ui/button/button.tsx b/react-heading/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-heading/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-heading/src/components/editor/ui/button/index.ts b/react-heading/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-heading/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-heading/src/components/editor/ui/image-upload-popover/index.ts b/react-heading/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-heading/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-heading/src/components/editor/ui/toolbar/index.ts b/react-heading/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-heading/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-heading/src/components/editor/ui/toolbar/toolbar.tsx b/react-heading/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-heading/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-heading/src/main.tsx b/react-heading/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-heading/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-heading/tsconfig.app.json b/react-heading/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-heading/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-heading/tsconfig.json b/react-heading/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-heading/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-heading/tsconfig.node.json b/react-heading/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-heading/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-heading/vite.config.ts b/react-heading/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-heading/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-highlight/.gitignore b/react-highlight/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-highlight/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-highlight/README.md b/react-highlight/README.md deleted file mode 100644 index b2c083a7f6..0000000000 --- a/react-highlight/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-highlight - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-highlight) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-highlight) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-highlight react-highlight -cd react-highlight -npm install -npm run dev -``` diff --git a/react-highlight/index.html b/react-highlight/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-highlight/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-highlight/package.json b/react-highlight/package.json deleted file mode 100644 index 5b2ee80a01..0000000000 --- a/react-highlight/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-highlight", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-highlight/src/App.tsx b/react-highlight/src/App.tsx deleted file mode 100644 index 2509b001f7..0000000000 --- a/react-highlight/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/highlight' - -export default function App() { - return -} diff --git a/react-highlight/src/app.css b/react-highlight/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-highlight/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-highlight/src/components/editor/examples/highlight/editor.tsx b/react-highlight/src/components/editor/examples/highlight/editor.tsx deleted file mode 100644 index f49a0436dc..0000000000 --- a/react-highlight/src/components/editor/examples/highlight/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-highlight' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-highlight/src/components/editor/examples/highlight/extension.ts b/react-highlight/src/components/editor/examples/highlight/extension.ts deleted file mode 100644 index abc131c3be..0000000000 --- a/react-highlight/src/components/editor/examples/highlight/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHighlight } from 'prosekit/extensions/highlight' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHighlight(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-highlight/src/components/editor/examples/highlight/index.ts b/react-highlight/src/components/editor/examples/highlight/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-highlight/src/components/editor/examples/highlight/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-highlight/src/components/editor/examples/highlight/toolbar.tsx b/react-highlight/src/components/editor/examples/highlight/toolbar.tsx deleted file mode 100644 index 13681ed44c..0000000000 --- a/react-highlight/src/components/editor/examples/highlight/toolbar.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - highlight: { - isActive: editor.marks.highlight.isActive(), - canExec: editor.commands.toggleHighlight.canExec(), - command: () => editor.commands.toggleHighlight(), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/react-highlight/src/components/editor/sample/sample-doc-highlight.ts b/react-highlight/src/components/editor/sample/sample-doc-highlight.ts deleted file mode 100644 index 0de1a1f7b2..0000000000 --- a/react-highlight/src/components/editor/sample/sample-doc-highlight.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'highlight', - }, - ], - text: 'This is highlighted text', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/react-highlight/src/components/editor/ui/button/button.tsx b/react-highlight/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-highlight/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-highlight/src/components/editor/ui/button/index.ts b/react-highlight/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-highlight/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-highlight/src/main.tsx b/react-highlight/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-highlight/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-highlight/tsconfig.app.json b/react-highlight/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-highlight/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-highlight/tsconfig.json b/react-highlight/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-highlight/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-highlight/tsconfig.node.json b/react-highlight/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-highlight/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-highlight/vite.config.ts b/react-highlight/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-highlight/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-horizontal-rule/.gitignore b/react-horizontal-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-horizontal-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-horizontal-rule/README.md b/react-horizontal-rule/README.md deleted file mode 100644 index c7c1993944..0000000000 --- a/react-horizontal-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-horizontal-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-horizontal-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-horizontal-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-horizontal-rule react-horizontal-rule -cd react-horizontal-rule -npm install -npm run dev -``` diff --git a/react-horizontal-rule/index.html b/react-horizontal-rule/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-horizontal-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-horizontal-rule/package.json b/react-horizontal-rule/package.json deleted file mode 100644 index 115b5221c5..0000000000 --- a/react-horizontal-rule/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-horizontal-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-horizontal-rule/src/App.tsx b/react-horizontal-rule/src/App.tsx deleted file mode 100644 index 974e387364..0000000000 --- a/react-horizontal-rule/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/horizontal-rule' - -export default function App() { - return -} diff --git a/react-horizontal-rule/src/app.css b/react-horizontal-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-horizontal-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx deleted file mode 100644 index cbf25168cf..0000000000 --- a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - return createEditor({ extension: defineExtension() }) - }, []) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts deleted file mode 100644 index 49b6121eeb..0000000000 --- a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHorizontalRule(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-horizontal-rule/src/components/editor/ui/button/button.tsx b/react-horizontal-rule/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-horizontal-rule/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-horizontal-rule/src/components/editor/ui/button/index.ts b/react-horizontal-rule/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-horizontal-rule/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/react-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/react-horizontal-rule/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-horizontal-rule/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx b/react-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-horizontal-rule/src/main.tsx b/react-horizontal-rule/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-horizontal-rule/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-horizontal-rule/tsconfig.app.json b/react-horizontal-rule/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-horizontal-rule/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-horizontal-rule/tsconfig.json b/react-horizontal-rule/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-horizontal-rule/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-horizontal-rule/tsconfig.node.json b/react-horizontal-rule/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-horizontal-rule/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-horizontal-rule/vite.config.ts b/react-horizontal-rule/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-horizontal-rule/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-image-view/.gitignore b/react-image-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-image-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-image-view/README.md b/react-image-view/README.md deleted file mode 100644 index 82f4507524..0000000000 --- a/react-image-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-image-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-image-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-image-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-image-view react-image-view -cd react-image-view -npm install -npm run dev -``` diff --git a/react-image-view/index.html b/react-image-view/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-image-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-image-view/package.json b/react-image-view/package.json deleted file mode 100644 index af1217ed4e..0000000000 --- a/react-image-view/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-image-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-image-view/src/App.tsx b/react-image-view/src/App.tsx deleted file mode 100644 index 46ede58891..0000000000 --- a/react-image-view/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/image-view' - -export default function App() { - return -} diff --git a/react-image-view/src/app.css b/react-image-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-image-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-image-view/src/components/editor/examples/image-view/editor.tsx b/react-image-view/src/components/editor/examples/image-view/editor.tsx deleted file mode 100644 index a0bb6d3f1e..0000000000 --- a/react-image-view/src/components/editor/examples/image-view/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-image' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-image-view/src/components/editor/examples/image-view/extension.ts b/react-image-view/src/components/editor/examples/image-view/extension.ts deleted file mode 100644 index a21febf634..0000000000 --- a/react-image-view/src/components/editor/examples/image-view/extension.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineImageUploadHandler } from 'prosekit/extensions/image' - -import { sampleUploader } from '../../sample/sample-uploader' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-image-view/src/components/editor/examples/image-view/index.ts b/react-image-view/src/components/editor/examples/image-view/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-image-view/src/components/editor/examples/image-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-image-view/src/components/editor/sample/sample-doc-image.ts b/react-image-view/src/components/editor/sample/sample-doc-image.ts deleted file mode 100644 index c97628339d..0000000000 --- a/react-image-view/src/components/editor/sample/sample-doc-image.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Paste or drop an image to upload it.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/white/200x200/1', - width: 160, - height: 160, - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/640x360/42', - width: 240, - height: 135, - }, - }, - ], -} diff --git a/react-image-view/src/components/editor/sample/sample-uploader.ts b/react-image-view/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/react-image-view/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/react-image-view/src/components/editor/ui/image-view/image-view.tsx b/react-image-view/src/components/editor/ui/image-view/image-view.tsx deleted file mode 100644 index 06da475774..0000000000 --- a/react-image-view/src/components/editor/ui/image-view/image-view.tsx +++ /dev/null @@ -1,94 +0,0 @@ -'use client' - -import { UploadTask } from 'prosekit/extensions/file' -import type { ImageAttrs } from 'prosekit/extensions/image' -import type { ReactNodeViewProps } from 'prosekit/react' -import { ResizableHandle, ResizableRoot } from 'prosekit/react/resizable' -import { useEffect, useState, type SyntheticEvent } from 'react' - -export default function ImageView(props: ReactNodeViewProps) { - const attrs = props.node.attrs as ImageAttrs - const url = attrs.src || '' - const uploading = url.startsWith('blob:') - - const [aspectRatio, setAspectRatio] = useState() - const [error, setError] = useState() - const [progress, setProgress] = useState(0) - - useEffect(() => { - if (!uploading) return - - const uploadTask = UploadTask.get(url) - if (!uploadTask) return - - let canceled = false - - uploadTask.finished.catch((error) => { - if (canceled) return - setError(String(error)) - }) - const unsubscribeProgress = uploadTask.subscribeProgress( - ({ loaded, total }) => { - if (canceled) return - setProgress(total ? loaded / total : 0) - }, - ) - - return () => { - canceled = true - unsubscribeProgress() - } - }, [url, uploading]) - - const handleImageLoad = (event: SyntheticEvent) => { - const img = event.target as HTMLImageElement - const { naturalWidth, naturalHeight } = img - const ratio = naturalWidth / naturalHeight - if (ratio && Number.isFinite(ratio)) { - setAspectRatio(ratio) - } - if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) { - props.setAttrs({ width: naturalWidth, height: naturalHeight }) - } - } - - return ( - props.setAttrs(event.detail)} - data-selected={props.selected ? '' : undefined} - className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid" - > - {url && !error && ( - upload preview - )} - {uploading && !error && ( -
-
-
{Math.round(progress * 100)}%
-
- )} - {error && ( -
-
-
- Failed to upload image -
-
- )} - -
-
-
- ) -} diff --git a/react-image-view/src/components/editor/ui/image-view/index.ts b/react-image-view/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index c4a95f9d3f..0000000000 --- a/react-image-view/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - defineReactNodeView, - type ReactNodeViewComponent, -} from 'prosekit/react' - -import ImageView from './image-view' - -export function defineImageView(): Extension { - return defineReactNodeView({ - name: 'image', - component: ImageView satisfies ReactNodeViewComponent, - }) -} diff --git a/react-image-view/src/main.tsx b/react-image-view/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-image-view/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-image-view/tsconfig.app.json b/react-image-view/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-image-view/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-image-view/tsconfig.json b/react-image-view/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-image-view/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-image-view/tsconfig.node.json b/react-image-view/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-image-view/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-image-view/vite.config.ts b/react-image-view/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-image-view/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-inline-menu/.gitignore b/react-inline-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-inline-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-inline-menu/README.md b/react-inline-menu/README.md deleted file mode 100644 index 7aef3d6362..0000000000 --- a/react-inline-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-inline-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-inline-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-inline-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-inline-menu react-inline-menu -cd react-inline-menu -npm install -npm run dev -``` diff --git a/react-inline-menu/index.html b/react-inline-menu/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-inline-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-inline-menu/package.json b/react-inline-menu/package.json deleted file mode 100644 index fa45986e6e..0000000000 --- a/react-inline-menu/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-inline-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-inline-menu/src/App.tsx b/react-inline-menu/src/App.tsx deleted file mode 100644 index 660285db3c..0000000000 --- a/react-inline-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/inline-menu' - -export default function App() { - return -} diff --git a/react-inline-menu/src/app.css b/react-inline-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-inline-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-inline-menu/src/components/editor/examples/inline-menu/editor.tsx b/react-inline-menu/src/components/editor/examples/inline-menu/editor.tsx deleted file mode 100644 index 7a23947606..0000000000 --- a/react-inline-menu/src/components/editor/examples/inline-menu/editor.tsx +++ /dev/null @@ -1,38 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-inline-menu' -import { InlineMenu } from '../../ui/inline-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - return createEditor({ extension: defineExtension(), defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/react-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/react-inline-menu/src/components/editor/examples/inline-menu/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/react-inline-menu/src/components/editor/examples/inline-menu/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/react-inline-menu/src/components/editor/examples/inline-menu/index.ts b/react-inline-menu/src/components/editor/examples/inline-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-inline-menu/src/components/editor/examples/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/react-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts deleted file mode 100644 index 62a5984cb0..0000000000 --- a/react-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const loremText = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'Try to select some text', - }, - ], - }, - ...Array.from({ length: 10 }, () => ({ - type: 'paragraph' as const, - content: [ - { - type: 'text' as const, - text: loremText, - }, - ], - })), - ], -} diff --git a/react-inline-menu/src/components/editor/ui/button/button.tsx b/react-inline-menu/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-inline-menu/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-inline-menu/src/components/editor/ui/button/index.ts b/react-inline-menu/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-inline-menu/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-inline-menu/src/components/editor/ui/inline-menu/index.ts b/react-inline-menu/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/react-inline-menu/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/react-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index af1b2bb2b7..0000000000 --- a/react-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/react' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/react/inline-popover' -import { useState } from 'react' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/react-inline-menu/src/main.tsx b/react-inline-menu/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-inline-menu/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-inline-menu/tsconfig.app.json b/react-inline-menu/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-inline-menu/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-inline-menu/tsconfig.json b/react-inline-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-inline-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-inline-menu/tsconfig.node.json b/react-inline-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-inline-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-inline-menu/vite.config.ts b/react-inline-menu/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-inline-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-italic/.gitignore b/react-italic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-italic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-italic/README.md b/react-italic/README.md deleted file mode 100644 index 1412b917f5..0000000000 --- a/react-italic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-italic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-italic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-italic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-italic react-italic -cd react-italic -npm install -npm run dev -``` diff --git a/react-italic/index.html b/react-italic/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-italic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-italic/package.json b/react-italic/package.json deleted file mode 100644 index d04ce3bd6d..0000000000 --- a/react-italic/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-italic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-italic/src/App.tsx b/react-italic/src/App.tsx deleted file mode 100644 index 7ce968b449..0000000000 --- a/react-italic/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/italic' - -export default function App() { - return -} diff --git a/react-italic/src/app.css b/react-italic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-italic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-italic/src/components/editor/examples/italic/editor.tsx b/react-italic/src/components/editor/examples/italic/editor.tsx deleted file mode 100644 index 5651947320..0000000000 --- a/react-italic/src/components/editor/examples/italic/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-italic' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-italic/src/components/editor/examples/italic/extension.ts b/react-italic/src/components/editor/examples/italic/extension.ts deleted file mode 100644 index a456b06aad..0000000000 --- a/react-italic/src/components/editor/examples/italic/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineItalic(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-italic/src/components/editor/examples/italic/index.ts b/react-italic/src/components/editor/examples/italic/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-italic/src/components/editor/examples/italic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-italic/src/components/editor/sample/sample-doc-italic.ts b/react-italic/src/components/editor/sample/sample-doc-italic.ts deleted file mode 100644 index fb99415b2c..0000000000 --- a/react-italic/src/components/editor/sample/sample-doc-italic.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/react-italic/src/components/editor/ui/button/button.tsx b/react-italic/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-italic/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-italic/src/components/editor/ui/button/index.ts b/react-italic/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-italic/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-italic/src/components/editor/ui/image-upload-popover/index.ts b/react-italic/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-italic/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-italic/src/components/editor/ui/toolbar/index.ts b/react-italic/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-italic/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-italic/src/components/editor/ui/toolbar/toolbar.tsx b/react-italic/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-italic/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-italic/src/main.tsx b/react-italic/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-italic/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-italic/tsconfig.app.json b/react-italic/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-italic/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-italic/tsconfig.json b/react-italic/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-italic/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-italic/tsconfig.node.json b/react-italic/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-italic/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-italic/vite.config.ts b/react-italic/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-italic/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-katex/.gitignore b/react-katex/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-katex/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-katex/README.md b/react-katex/README.md deleted file mode 100644 index eade88a0db..0000000000 --- a/react-katex/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-katex - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-katex) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-katex) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-katex react-katex -cd react-katex -npm install -npm run dev -``` diff --git a/react-katex/index.html b/react-katex/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-katex/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-katex/package.json b/react-katex/package.json deleted file mode 100644 index 635c9b2517..0000000000 --- a/react-katex/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-react-katex", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.47", - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-katex/src/App.tsx b/react-katex/src/App.tsx deleted file mode 100644 index 2a28c7c7d7..0000000000 --- a/react-katex/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/katex' - -export default function App() { - return -} diff --git a/react-katex/src/app.css b/react-katex/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-katex/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-katex/src/components/editor/examples/katex/editor.tsx b/react-katex/src/components/editor/examples/katex/editor.tsx deleted file mode 100644 index 41d22fcbde..0000000000 --- a/react-katex/src/components/editor/examples/katex/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-tex' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-katex/src/components/editor/examples/katex/extension.ts b/react-katex/src/components/editor/examples/katex/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/react-katex/src/components/editor/examples/katex/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-katex/src/components/editor/examples/katex/index.ts b/react-katex/src/components/editor/examples/katex/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-katex/src/components/editor/examples/katex/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-katex/src/components/editor/sample/katex.ts b/react-katex/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/react-katex/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/react-katex/src/components/editor/sample/sample-doc-tex.ts b/react-katex/src/components/editor/sample/sample-doc-tex.ts deleted file mode 100644 index 21ccf3e94e..0000000000 --- a/react-katex/src/components/editor/sample/sample-doc-tex.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Inline equations' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Block equations' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: 'The Gaussian integral:' }], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - ], -} diff --git a/react-katex/src/main.tsx b/react-katex/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-katex/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-katex/tsconfig.app.json b/react-katex/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-katex/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-katex/tsconfig.json b/react-katex/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-katex/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-katex/tsconfig.node.json b/react-katex/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-katex/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-katex/vite.config.ts b/react-katex/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-katex/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-keymap/.gitignore b/react-keymap/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-keymap/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-keymap/README.md b/react-keymap/README.md deleted file mode 100644 index a1dd4b7b45..0000000000 --- a/react-keymap/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-keymap - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-keymap) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-keymap) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-keymap react-keymap -cd react-keymap -npm install -npm run dev -``` diff --git a/react-keymap/index.html b/react-keymap/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-keymap/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-keymap/package.json b/react-keymap/package.json deleted file mode 100644 index 1d7d027b27..0000000000 --- a/react-keymap/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-keymap", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-keymap/src/App.tsx b/react-keymap/src/App.tsx deleted file mode 100644 index da3b6ebb09..0000000000 --- a/react-keymap/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/keymap' - -export default function App() { - return -} diff --git a/react-keymap/src/app.css b/react-keymap/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-keymap/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-keymap/src/components/editor/examples/keymap/editor.tsx b/react-keymap/src/components/editor/examples/keymap/editor.tsx deleted file mode 100644 index 00bc32b314..0000000000 --- a/react-keymap/src/components/editor/examples/keymap/editor.tsx +++ /dev/null @@ -1,54 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useCallback, useMemo, useState } from 'react' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - const [submissions, setSubmissions] = useState([]) - - const pushSubmission = useCallback( - (hotkey: string) => { - const docString = JSON.stringify(editor.getDocJSON()) - const submission = `${new Date().toISOString()}\t${hotkey}\n${docString}` - setSubmissions((prev) => [...prev, submission]) - }, - [editor], - ) - - return ( - -
- -
-
-
-
-
- Submit Records -
    - {submissions.map((submission, index) => ( -
  1. -
    {submission}
    -
  2. - ))} -
- {submissions.length === 0 &&
No submissions yet
} -
-
- ) -} diff --git a/react-keymap/src/components/editor/examples/keymap/extension.ts b/react-keymap/src/components/editor/examples/keymap/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/react-keymap/src/components/editor/examples/keymap/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/react-keymap/src/components/editor/examples/keymap/index.ts b/react-keymap/src/components/editor/examples/keymap/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-keymap/src/components/editor/examples/keymap/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-keymap/src/components/editor/examples/keymap/toolbar.tsx b/react-keymap/src/components/editor/examples/keymap/toolbar.tsx deleted file mode 100644 index d76e237a60..0000000000 --- a/react-keymap/src/components/editor/examples/keymap/toolbar.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client' - -import { useState } from 'react' - -import { Button } from '../../ui/button' - -import { useSubmitKeymap } from './use-submit-keymap' - -export default function Toolbar(props: { onSubmit: (hotkey: string) => void }) { - const [hotkey, setHotkey] = useState<'Shift-Enter' | 'Enter'>('Shift-Enter') - useSubmitKeymap(hotkey, props.onSubmit) - - return ( -
- - - -
- ) -} diff --git a/react-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts b/react-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts deleted file mode 100644 index a163d7ebba..0000000000 --- a/react-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Keymap } from 'prosekit/core' -import { useKeymap } from 'prosekit/react' -import { useMemo } from 'react' - -export function useSubmitKeymap( - hotkey: 'Shift-Enter' | 'Enter', - onSubmit: (hotkey: string) => void, -) { - const keymap: Keymap = useMemo(() => { - return { - [hotkey]: () => { - onSubmit(hotkey) - return true - }, - } - }, [hotkey, onSubmit]) - - useKeymap(keymap) -} diff --git a/react-keymap/src/components/editor/ui/button/button.tsx b/react-keymap/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-keymap/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-keymap/src/components/editor/ui/button/index.ts b/react-keymap/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-keymap/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-keymap/src/main.tsx b/react-keymap/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-keymap/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-keymap/tsconfig.app.json b/react-keymap/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-keymap/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-keymap/tsconfig.json b/react-keymap/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-keymap/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-keymap/tsconfig.node.json b/react-keymap/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-keymap/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-keymap/vite.config.ts b/react-keymap/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-keymap/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-link-mark-view/.gitignore b/react-link-mark-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-link-mark-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-link-mark-view/README.md b/react-link-mark-view/README.md deleted file mode 100644 index d160af1a3c..0000000000 --- a/react-link-mark-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-link-mark-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-link-mark-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-link-mark-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-link-mark-view react-link-mark-view -cd react-link-mark-view -npm install -npm run dev -``` diff --git a/react-link-mark-view/index.html b/react-link-mark-view/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-link-mark-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-link-mark-view/package.json b/react-link-mark-view/package.json deleted file mode 100644 index c5fd61a1bb..0000000000 --- a/react-link-mark-view/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-link-mark-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-link-mark-view/src/App.tsx b/react-link-mark-view/src/App.tsx deleted file mode 100644 index 8a8685678d..0000000000 --- a/react-link-mark-view/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/link-mark-view' - -export default function App() { - return -} diff --git a/react-link-mark-view/src/app.css b/react-link-mark-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-link-mark-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx b/react-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx deleted file mode 100644 index a78baa04e1..0000000000 --- a/react-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-link-mark-view' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/react-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts deleted file mode 100644 index 697375ed00..0000000000 --- a/react-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineReactMarkView } from 'prosekit/react' - -import LinkView from './link-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineReactMarkView({ - name: 'link', - component: LinkView, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/react-link-mark-view/src/components/editor/examples/link-mark-view/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-link-mark-view/src/components/editor/examples/link-mark-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx b/react-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx deleted file mode 100644 index 9a87078d64..0000000000 --- a/react-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx +++ /dev/null @@ -1,47 +0,0 @@ -'use client' - -import type { ReactMarkViewProps } from 'prosekit/react' -import { useEffect, useState } from 'react' - -const colors = [ - '#f06292', - '#ba68c8', - '#9575cd', - '#7986cb', - '#64b5f6', - '#4fc3f7', - '#4dd0e1', - '#4db6ac', - '#81c784', - '#aed581', - '#ffb74d', - '#ffa726', - '#ff8a65', - '#d4e157', - '#ffd54f', - '#ffecb3', -] - -function pickRandomColor() { - return colors[Math.floor(Math.random() * colors.length)] -} - -export default function Link(props: ReactMarkViewProps) { - const [color, setColor] = useState(colors[0]) - const href = props.mark.attrs.href as string - - useEffect(() => { - const interval = setInterval(() => { - setColor(pickRandomColor()) - }, 1000) - return () => clearInterval(interval) - }, []) - - return ( - - ) -} diff --git a/react-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/react-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts deleted file mode 100644 index 57abd09dd6..0000000000 --- a/react-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is a link that changes color every second: ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/react-link-mark-view/src/main.tsx b/react-link-mark-view/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-link-mark-view/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-link-mark-view/tsconfig.app.json b/react-link-mark-view/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-link-mark-view/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-link-mark-view/tsconfig.json b/react-link-mark-view/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-link-mark-view/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-link-mark-view/tsconfig.node.json b/react-link-mark-view/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-link-mark-view/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-link-mark-view/vite.config.ts b/react-link-mark-view/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-link-mark-view/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-link/.gitignore b/react-link/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-link/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-link/README.md b/react-link/README.md deleted file mode 100644 index 4eb974fbe0..0000000000 --- a/react-link/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-link - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-link) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-link) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-link react-link -cd react-link -npm install -npm run dev -``` diff --git a/react-link/index.html b/react-link/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-link/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-link/package.json b/react-link/package.json deleted file mode 100644 index 488fda2dfe..0000000000 --- a/react-link/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-link", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-link/src/App.tsx b/react-link/src/App.tsx deleted file mode 100644 index 1cf0f24636..0000000000 --- a/react-link/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/link' - -export default function App() { - return -} diff --git a/react-link/src/app.css b/react-link/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-link/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-link/src/components/editor/examples/link/editor.tsx b/react-link/src/components/editor/examples/link/editor.tsx deleted file mode 100644 index 8d9fc1bee4..0000000000 --- a/react-link/src/components/editor/examples/link/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-link' -import { InlineMenu } from '../../ui/inline-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/react-link/src/components/editor/examples/link/extension.ts b/react-link/src/components/editor/examples/link/extension.ts deleted file mode 100644 index bf499147da..0000000000 --- a/react-link/src/components/editor/examples/link/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLink } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-link/src/components/editor/examples/link/index.ts b/react-link/src/components/editor/examples/link/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-link/src/components/editor/examples/link/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-link/src/components/editor/sample/sample-doc-link.ts b/react-link/src/components/editor/sample/sample-doc-link.ts deleted file mode 100644 index 726cf334fd..0000000000 --- a/react-link/src/components/editor/sample/sample-doc-link.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is an ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/react-link/src/components/editor/ui/button/button.tsx b/react-link/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-link/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-link/src/components/editor/ui/button/index.ts b/react-link/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-link/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-link/src/components/editor/ui/inline-menu/index.ts b/react-link/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/react-link/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/react-link/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-link/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index af1b2bb2b7..0000000000 --- a/react-link/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/react' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/react/inline-popover' -import { useState } from 'react' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/react-link/src/main.tsx b/react-link/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-link/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-link/tsconfig.app.json b/react-link/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-link/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-link/tsconfig.json b/react-link/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-link/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-link/tsconfig.node.json b/react-link/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-link/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-link/vite.config.ts b/react-link/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-link/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-list-custom-checkbox/.gitignore b/react-list-custom-checkbox/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-list-custom-checkbox/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-list-custom-checkbox/README.md b/react-list-custom-checkbox/README.md deleted file mode 100644 index 9de808f76b..0000000000 --- a/react-list-custom-checkbox/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-list-custom-checkbox - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-list-custom-checkbox) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-list-custom-checkbox) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-list-custom-checkbox react-list-custom-checkbox -cd react-list-custom-checkbox -npm install -npm run dev -``` diff --git a/react-list-custom-checkbox/index.html b/react-list-custom-checkbox/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-list-custom-checkbox/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-list-custom-checkbox/package.json b/react-list-custom-checkbox/package.json deleted file mode 100644 index 3d12f2f11d..0000000000 --- a/react-list-custom-checkbox/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-list-custom-checkbox", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-list-custom-checkbox/src/App.tsx b/react-list-custom-checkbox/src/App.tsx deleted file mode 100644 index 96b82e9a84..0000000000 --- a/react-list-custom-checkbox/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/list-custom-checkbox' - -export default function App() { - return -} diff --git a/react-list-custom-checkbox/src/app.css b/react-list-custom-checkbox/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-list-custom-checkbox/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css deleted file mode 100644 index ec631b72ad..0000000000 --- a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css +++ /dev/null @@ -1,75 +0,0 @@ -div[data-custom-list-css-enabled] - .ProseMirror - .prosemirror-flat-list[data-list-kind='task'] { - & > .list-marker label { - box-sizing: border-box; - display: flex; - position: relative; - left: calc(var(--spacing) * -0.5); - align-items: center; - cursor: pointer; - transition: transform 0.15s ease-in-out; - - &:hover { - transform: scale(1.1); - } - - &::after { - position: absolute; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - content: ''; - color: var(--color-white); - opacity: 0; - } - - /* https://api.iconify.design/lucide.css?icons=check */ - &::after { - display: inline-block; - background-color: currentColor; - -webkit-mask-image: var(--svg); - mask-image: var(--svg); - -webkit-mask-repeat: no-repeat; - mask-repeat: no-repeat; - -webkit-mask-size: 100% 100%; - mask-size: 100% 100%; - --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); - } - - & input { - box-sizing: border-box; - appearance: none; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - margin: 0; - border-width: 1px; - border-style: solid; - border-radius: var(--radius-md); - border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); - box-shadow: var(--shadow-sm); - cursor: pointer; - transition: all 0.15s ease-in-out; - - &:hover { - box-shadow: var(--shadow-md); - } - - &:checked { - border-color: var(--color-red-500); - background-color: var(--color-red-500); - } - } - } - - &[data-list-checked] > .list-marker label { - &::after { - opacity: 1; - } - } - - &[data-list-checked] { - color: var(--color-gray-400); - text-decoration: line-through; - text-decoration-color: var(--color-gray-400); - } -} diff --git a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx deleted file mode 100644 index c9765e7bd6..0000000000 --- a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import './custom-list.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-list-custom-checkbox' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ - extension, - defaultContent, - }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/react-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts deleted file mode 100644 index 972611aed1..0000000000 --- a/react-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', - }, - { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, - { type: 'text', text: ' for the styles.' }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Completed Task' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Incomplete Task' }], - }, - ], - }, - ], -} diff --git a/react-list-custom-checkbox/src/components/editor/ui/button/button.tsx b/react-list-custom-checkbox/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-list-custom-checkbox/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-list-custom-checkbox/src/components/editor/ui/button/index.ts b/react-list-custom-checkbox/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-list-custom-checkbox/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/react-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx b/react-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-list-custom-checkbox/src/main.tsx b/react-list-custom-checkbox/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-list-custom-checkbox/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-list-custom-checkbox/tsconfig.app.json b/react-list-custom-checkbox/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-list-custom-checkbox/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-list-custom-checkbox/tsconfig.json b/react-list-custom-checkbox/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-list-custom-checkbox/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-list-custom-checkbox/tsconfig.node.json b/react-list-custom-checkbox/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-list-custom-checkbox/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-list-custom-checkbox/vite.config.ts b/react-list-custom-checkbox/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-list-custom-checkbox/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-list/.gitignore b/react-list/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-list/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-list/README.md b/react-list/README.md deleted file mode 100644 index f79af22497..0000000000 --- a/react-list/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-list - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-list) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-list) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-list react-list -cd react-list -npm install -npm run dev -``` diff --git a/react-list/index.html b/react-list/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-list/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-list/package.json b/react-list/package.json deleted file mode 100644 index da7a569c15..0000000000 --- a/react-list/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-list", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-list/src/App.tsx b/react-list/src/App.tsx deleted file mode 100644 index 73f050ef0c..0000000000 --- a/react-list/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/list' - -export default function App() { - return -} diff --git a/react-list/src/app.css b/react-list/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-list/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-list/src/components/editor/examples/list/editor.tsx b/react-list/src/components/editor/examples/list/editor.tsx deleted file mode 100644 index 89a19a2a23..0000000000 --- a/react-list/src/components/editor/examples/list/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-list' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-list/src/components/editor/examples/list/extension.ts b/react-list/src/components/editor/examples/list/extension.ts deleted file mode 100644 index f66bae6ff7..0000000000 --- a/react-list/src/components/editor/examples/list/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineList } from 'prosekit/extensions/list' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineList(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-list/src/components/editor/examples/list/index.ts b/react-list/src/components/editor/examples/list/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-list/src/components/editor/examples/list/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-list/src/components/editor/sample/sample-doc-list.ts b/react-list/src/components/editor/sample/sample-doc-list.ts deleted file mode 100644 index 091bc37185..0000000000 --- a/react-list/src/components/editor/sample/sample-doc-list.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Ordered List' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'toggle', collapsed: true }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, - { - type: 'list', - attrs: { - kind: 'bullet', - }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, - ], - }, - ], - }, - ], -} diff --git a/react-list/src/components/editor/ui/button/button.tsx b/react-list/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-list/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-list/src/components/editor/ui/button/index.ts b/react-list/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-list/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-list/src/components/editor/ui/image-upload-popover/index.ts b/react-list/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-list/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-list/src/components/editor/ui/toolbar/index.ts b/react-list/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-list/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-list/src/components/editor/ui/toolbar/toolbar.tsx b/react-list/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-list/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-list/src/main.tsx b/react-list/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-list/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-list/tsconfig.app.json b/react-list/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-list/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-list/tsconfig.json b/react-list/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-list/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-list/tsconfig.node.json b/react-list/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-list/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-list/vite.config.ts b/react-list/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-list/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-loro/.gitignore b/react-loro/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-loro/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-loro/README.md b/react-loro/README.md deleted file mode 100644 index 94ed80130d..0000000000 --- a/react-loro/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-loro - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-loro) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-loro) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-loro react-loro -cd react-loro -npm install -npm run dev -``` diff --git a/react-loro/index.html b/react-loro/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-loro/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-loro/package.json b/react-loro/package.json deleted file mode 100644 index 1c553d0ba3..0000000000 --- a/react-loro/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "example-react-loro", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "loro-crdt": "^1.12.1", - "loro-prosemirror": "^0.4.3", - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-wasm": "^3.6.0" - } -} diff --git a/react-loro/src/App.tsx b/react-loro/src/App.tsx deleted file mode 100644 index 71d2a6b080..0000000000 --- a/react-loro/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/loro' - -export default function App() { - return -} diff --git a/react-loro/src/app.css b/react-loro/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-loro/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-loro/src/components/editor/examples/loro/editor-component.tsx b/react-loro/src/components/editor/examples/loro/editor-component.tsx deleted file mode 100644 index e6df130c78..0000000000 --- a/react-loro/src/components/editor/examples/loro/editor-component.tsx +++ /dev/null @@ -1,38 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/loro/style.css' - -import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function EditorComponent(props: { - loro: LoroDocType - awareness: CursorAwareness -}) { - const editor = useMemo(() => { - const extension = defineExtension(props.loro, props.awareness) - return createEditor({ extension }) - }, [props.loro, props.awareness]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-loro/src/components/editor/examples/loro/editor.tsx b/react-loro/src/components/editor/examples/loro/editor.tsx deleted file mode 100644 index 5357d78b68..0000000000 --- a/react-loro/src/components/editor/examples/loro/editor.tsx +++ /dev/null @@ -1,65 +0,0 @@ -'use client' - -import { LoroDoc, type AwarenessListener } from 'loro-crdt' -import { CursorAwareness, type LoroDocType } from 'loro-prosemirror' -import { useEffect, useState } from 'react' - -import EditorComponent from './editor-component' - -export default function Page() { - const { loroA, awarenessA, loroB, awarenessB } = useLoroDocs() - - return ( -
- - -
- ) -} - -function useLoroDocs() { - const [loroState] = useState(() => { - const loroA: LoroDocType = new LoroDoc() - const loroB: LoroDocType = new LoroDoc() - - const idA = loroA.peerIdStr - const idB = loroB.peerIdStr - - const awarenessA = new CursorAwareness(idA) - const awarenessB = new CursorAwareness(idB) - - return { loroA, loroB, idA, idB, awarenessA, awarenessB } - }) - - useEffect(() => { - const { loroA, loroB, idA, idB, awarenessA, awarenessB } = loroState - loroA.import(loroB.export({ mode: 'update' })) - loroB.import(loroA.export({ mode: 'update' })) - const unsubscribeA = loroA.subscribeLocalUpdates((updates) => { - loroB.import(updates) - }) - const unsubscribeB = loroB.subscribeLocalUpdates((updates) => { - loroA.import(updates) - }) - const awarenessAListener: AwarenessListener = (_, origin) => { - if (origin === 'local') { - awarenessB.apply(awarenessA.encode([idA])) - } - } - const awarenessBListener: AwarenessListener = (_, origin) => { - if (origin === 'local') { - awarenessA.apply(awarenessB.encode([idB])) - } - } - awarenessA.addListener(awarenessAListener) - awarenessB.addListener(awarenessBListener) - return () => { - awarenessA.removeListener(awarenessAListener) - awarenessB.removeListener(awarenessBListener) - unsubscribeA() - unsubscribeB() - } - }, [loroState]) - - return loroState -} diff --git a/react-loro/src/components/editor/examples/loro/extension.ts b/react-loro/src/components/editor/examples/loro/extension.ts deleted file mode 100644 index 5a85c5e168..0000000000 --- a/react-loro/src/components/editor/examples/loro/extension.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineLoro } from 'prosekit/extensions/loro' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { - return union([ - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineLoro({ doc, awareness }), - ]) -} - -export type EditorExtension = ReturnType diff --git a/react-loro/src/components/editor/examples/loro/index.ts b/react-loro/src/components/editor/examples/loro/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-loro/src/components/editor/examples/loro/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-loro/src/components/editor/ui/button/button.tsx b/react-loro/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-loro/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-loro/src/components/editor/ui/button/index.ts b/react-loro/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-loro/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-loro/src/components/editor/ui/image-upload-popover/index.ts b/react-loro/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-loro/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-loro/src/components/editor/ui/toolbar/index.ts b/react-loro/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-loro/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-loro/src/components/editor/ui/toolbar/toolbar.tsx b/react-loro/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-loro/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-loro/src/main.tsx b/react-loro/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-loro/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-loro/tsconfig.app.json b/react-loro/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-loro/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-loro/tsconfig.json b/react-loro/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-loro/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-loro/tsconfig.node.json b/react-loro/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-loro/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-loro/vite.config.ts b/react-loro/vite.config.ts deleted file mode 100644 index fb354b9350..0000000000 --- a/react-loro/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import wasm from 'vite-plugin-wasm' -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [wasm(), react(), tailwindcss()], -}) diff --git a/react-mark-rule/.gitignore b/react-mark-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-mark-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-mark-rule/README.md b/react-mark-rule/README.md deleted file mode 100644 index a3e59a6610..0000000000 --- a/react-mark-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-mark-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-mark-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-mark-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-mark-rule react-mark-rule -cd react-mark-rule -npm install -npm run dev -``` diff --git a/react-mark-rule/index.html b/react-mark-rule/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-mark-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-mark-rule/package.json b/react-mark-rule/package.json deleted file mode 100644 index 5ef046547d..0000000000 --- a/react-mark-rule/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-mark-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-mark-rule/src/App.tsx b/react-mark-rule/src/App.tsx deleted file mode 100644 index 4e93a4bf60..0000000000 --- a/react-mark-rule/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/mark-rule' - -export default function App() { - return -} diff --git a/react-mark-rule/src/app.css b/react-mark-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-mark-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-mark-rule/src/components/editor/examples/mark-rule/editor.tsx b/react-mark-rule/src/components/editor/examples/mark-rule/editor.tsx deleted file mode 100644 index c17d11fd22..0000000000 --- a/react-mark-rule/src/components/editor/examples/mark-rule/editor.tsx +++ /dev/null @@ -1,30 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/react-mark-rule/src/components/editor/examples/mark-rule/extension.ts deleted file mode 100644 index 4a1de40783..0000000000 --- a/react-mark-rule/src/components/editor/examples/mark-rule/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - defineBaseCommands, - defineBaseKeymap, - defineHistory, - union, -} from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { definePlaceholder } from 'prosekit/extensions/placeholder' -import { defineText } from 'prosekit/extensions/text' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -import { defineIssueLink } from './issue-link' - -export function defineExtension() { - return union( - defineDoc(), - defineText(), - defineParagraph(), - defineHistory(), - defineBaseKeymap(), - defineBaseCommands(), - defineVirtualSelection(), - defineLinkSpec(), - defineLinkMarkRule(), - definePlaceholder({ placeholder: 'Try typing #123' }), - defineIssueLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-mark-rule/src/components/editor/examples/mark-rule/index.ts b/react-mark-rule/src/components/editor/examples/mark-rule/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-mark-rule/src/components/editor/examples/mark-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/react-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts deleted file mode 100644 index 3840b5e53d..0000000000 --- a/react-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { defineMarkSpec, union } from 'prosekit/core' -import { defineMarkRule } from 'prosekit/extensions/mark-rule' - -export function defineIssueLink() { - return union( - defineMarkSpec({ - name: 'issueLink', - inclusive: false, - attrs: { - issueNumber: {}, - }, - toDOM(node) { - const issueNumber = node.attrs.issueNumber as number - return [ - 'a', - { - href: `https://example.com/issues/${issueNumber}`, - title: `Issue #${issueNumber}`, - }, - 0, - ] - }, - }), - defineMarkRule({ - regex: /#(\d+)/g, - type: 'issueLink', - attrs: (match) => { - return { issueNumber: Number.parseInt(match[1] || '0') } - }, - }), - ) -} diff --git a/react-mark-rule/src/main.tsx b/react-mark-rule/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-mark-rule/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-mark-rule/tsconfig.app.json b/react-mark-rule/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-mark-rule/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-mark-rule/tsconfig.json b/react-mark-rule/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-mark-rule/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-mark-rule/tsconfig.node.json b/react-mark-rule/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-mark-rule/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-mark-rule/vite.config.ts b/react-mark-rule/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-mark-rule/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-minimal/.gitignore b/react-minimal/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-minimal/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-minimal/README.md b/react-minimal/README.md deleted file mode 100644 index 89a82436a7..0000000000 --- a/react-minimal/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-minimal - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-minimal) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-minimal) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-minimal react-minimal -cd react-minimal -npm install -npm run dev -``` diff --git a/react-minimal/index.html b/react-minimal/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-minimal/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-minimal/package.json b/react-minimal/package.json deleted file mode 100644 index d4c12787fc..0000000000 --- a/react-minimal/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-minimal", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-minimal/src/App.tsx b/react-minimal/src/App.tsx deleted file mode 100644 index 523aea224a..0000000000 --- a/react-minimal/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/minimal' - -export default function App() { - return -} diff --git a/react-minimal/src/app.css b/react-minimal/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-minimal/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-minimal/src/components/editor/examples/minimal/editor.tsx b/react-minimal/src/components/editor/examples/minimal/editor.tsx deleted file mode 100644 index fd22ae2a62..0000000000 --- a/react-minimal/src/components/editor/examples/minimal/editor.tsx +++ /dev/null @@ -1,22 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
- ) -} diff --git a/react-minimal/src/components/editor/examples/minimal/index.ts b/react-minimal/src/components/editor/examples/minimal/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-minimal/src/components/editor/examples/minimal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-minimal/src/main.tsx b/react-minimal/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-minimal/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-minimal/tsconfig.app.json b/react-minimal/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-minimal/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-minimal/tsconfig.json b/react-minimal/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-minimal/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-minimal/tsconfig.node.json b/react-minimal/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-minimal/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-minimal/vite.config.ts b/react-minimal/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-minimal/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-page/.gitignore b/react-page/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-page/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-page/README.md b/react-page/README.md deleted file mode 100644 index b384224910..0000000000 --- a/react-page/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-page - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-page) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-page) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-page react-page -cd react-page -npm install -npm run dev -``` diff --git a/react-page/index.html b/react-page/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-page/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-page/package.json b/react-page/package.json deleted file mode 100644 index a4c2e39ecf..0000000000 --- a/react-page/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-page", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-page/src/App.tsx b/react-page/src/App.tsx deleted file mode 100644 index b55eaee6c8..0000000000 --- a/react-page/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/page' - -export default function App() { - return -} diff --git a/react-page/src/app.css b/react-page/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-page/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-page/src/components/editor/examples/page/editor.tsx b/react-page/src/components/editor/examples/page/editor.tsx deleted file mode 100644 index 13dbbec432..0000000000 --- a/react-page/src/components/editor/examples/page/editor.tsx +++ /dev/null @@ -1,49 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/page/style.css' -import './zoom.css' - -import { clsx, createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo, useState } from 'react' - -import { sampleContent } from '../../sample/sample-doc-page' - -import { defineExtension } from './extension' -import PaperController from './paper-controller' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ - extension, - defaultContent, - }) - }, [defaultContent]) - - const [zoom, setZoom] = useState(50) - - return ( - -
- -
-
- - ) -} diff --git a/react-page/src/components/editor/examples/page/extension.ts b/react-page/src/components/editor/examples/page/extension.ts deleted file mode 100644 index edf01e897b..0000000000 --- a/react-page/src/components/editor/examples/page/extension.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePageBreak } from 'prosekit/extensions/page' - -export function defineExtension() { - return union(defineBasicExtension(), definePageBreak()) -} - -export type EditorExtension = ReturnType diff --git a/react-page/src/components/editor/examples/page/index.ts b/react-page/src/components/editor/examples/page/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-page/src/components/editor/examples/page/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-page/src/components/editor/examples/page/paper-controller.tsx b/react-page/src/components/editor/examples/page/paper-controller.tsx deleted file mode 100644 index f79ac700b4..0000000000 --- a/react-page/src/components/editor/examples/page/paper-controller.tsx +++ /dev/null @@ -1,142 +0,0 @@ -'use client' - -import { - definePageRendering, - type PageRenderingOptions, -} from 'prosekit/extensions/page' -import { useExtension } from 'prosekit/react' -import { useEffect, useId, useMemo, useState } from 'react' - -// Paper sizes in pixels at 96 DPI -const PAPER_SIZES = { - A3: { short: 1123, long: 1587 }, - A4: { short: 794, long: 1123 }, - A5: { short: 559, long: 794 }, - B4: { short: 945, long: 1334 }, - B5: { short: 665, long: 945 }, - letter: { short: 816, long: 1056 }, -} as const - -type PaperSize = keyof typeof PAPER_SIZES -type Orientation = 'portrait' | 'landscape' - -export default function PaperController({ - zoom, - setZoom, -}: { - zoom: number - setZoom: (zoom: number) => void -}) { - const id = useId() - const [paperSize, setPaperSize] = useState('A4') - const [orientation, setOrientation] = useState('portrait') - const [margin, setMargin] = useState(70) - const [enablePageLayout, setEnablePageLayout] = useState(true) - - const pageRenderingOptions: PageRenderingOptions = useMemo(() => { - const { short, long } = PAPER_SIZES[paperSize] - const pageWidth = orientation === 'portrait' ? short : long - const pageHeight = orientation === 'portrait' ? long : short - - return { - pageWidth, - pageHeight, - marginTop: margin, - marginRight: margin, - marginBottom: margin, - marginLeft: margin, - } - }, [paperSize, orientation, margin]) - - useEffect(() => { - const styleId = 'print-page-style' - let style = document.getElementById(styleId) as HTMLStyleElement | null - if (!style) { - style = document.createElement('style') - style.id = styleId - document.head.appendChild(style) - } - style.textContent = `@page { size: ${paperSize} ${orientation}; margin: 0; }` - - return () => { - style.textContent = '' - } - }, [paperSize, orientation]) - - const extension = useMemo(() => { - return enablePageLayout ? definePageRendering(pageRenderingOptions) : null - }, [pageRenderingOptions, enablePageLayout]) - - useExtension(extension) - - return ( -
- - - - - - - - - - -
- ) -} diff --git a/react-page/src/components/editor/examples/page/zoom.css b/react-page/src/components/editor/examples/page/zoom.css deleted file mode 100644 index bd81302639..0000000000 --- a/react-page/src/components/editor/examples/page/zoom.css +++ /dev/null @@ -1,9 +0,0 @@ -div[data-editor-zoom] { - zoom: var(--zoom); -} - -@media print { - div[data-editor-zoom] { - zoom: 1; - } -} diff --git a/react-page/src/components/editor/sample/sample-doc-page.ts b/react-page/src/components/editor/sample/sample-doc-page.ts deleted file mode 100644 index 60e78ac18e..0000000000 --- a/react-page/src/components/editor/sample/sample-doc-page.ts +++ /dev/null @@ -1,98 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Page Layout Demo' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is the first page.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The content below will be on a new page because of a page break. You can insert a page break by pressing Command+Enter on Mac or Ctrl+Enter on Windows and Linux.', - }, - ], - }, - { type: 'pageBreak' }, - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Page 2' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is the second page.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'When the content on a page exceeds the available height, it will automatically flow to the next page. This is similar to how traditional word processors like Microsoft Word handle pagination.', - }, - ], - }, - { type: 'image', attrs: { src: 'https://placehold.co/600x500' } }, - { type: 'image', attrs: { src: 'https://placehold.co/600x500' } }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The images above exceed the available height on the second page, so they automatically flow to the next page.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Known Limitation' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Page breaks only occur between block elements. A single block taller than the remaining space on the page will overflow to the next page rather than split. In other words, you cannot split a node like paragraph or a table across pages. The paragraph below demonstrates this.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'This is a very long paragraph that demonstrates the limitation of block-level pagination.', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [{ type: 'italic' }], - text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.', - }, - ], - }, - ], -} diff --git a/react-page/src/main.tsx b/react-page/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-page/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-page/tsconfig.app.json b/react-page/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-page/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-page/tsconfig.json b/react-page/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-page/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-page/tsconfig.node.json b/react-page/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-page/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-page/vite.config.ts b/react-page/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-page/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-placeholder/.gitignore b/react-placeholder/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-placeholder/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-placeholder/README.md b/react-placeholder/README.md deleted file mode 100644 index 27cbbdd306..0000000000 --- a/react-placeholder/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-placeholder - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-placeholder) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-placeholder) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-placeholder react-placeholder -cd react-placeholder -npm install -npm run dev -``` diff --git a/react-placeholder/index.html b/react-placeholder/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-placeholder/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-placeholder/package.json b/react-placeholder/package.json deleted file mode 100644 index 3ee8b24119..0000000000 --- a/react-placeholder/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-placeholder", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-placeholder/src/App.tsx b/react-placeholder/src/App.tsx deleted file mode 100644 index 919da8503a..0000000000 --- a/react-placeholder/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/placeholder' - -export default function App() { - return -} diff --git a/react-placeholder/src/app.css b/react-placeholder/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-placeholder/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-placeholder/src/components/editor/examples/placeholder/editor.tsx b/react-placeholder/src/components/editor/examples/placeholder/editor.tsx deleted file mode 100644 index 1ff28c3752..0000000000 --- a/react-placeholder/src/components/editor/examples/placeholder/editor.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, jsonFromNode, type NodeJSON } from 'prosekit/core' -import type { ProseMirrorNode } from 'prosekit/pm/model' -import { ProseKit, useDocChange } from 'prosekit/react' -import { useCallback, useMemo } from 'react' - -import { defineExtension } from './extension' - -export default function Editor(props: { - initialContent?: NodeJSON - onDocUpdate?: (doc: NodeJSON) => void -}) { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent: props.initialContent }) - }, [props.initialContent]) - - const { onDocUpdate } = props - const handleDocChange = useCallback( - (doc: ProseMirrorNode) => onDocUpdate?.(jsonFromNode(doc)), - [onDocUpdate], - ) - useDocChange(handleDocChange, { editor }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-placeholder/src/components/editor/examples/placeholder/extension.ts b/react-placeholder/src/components/editor/examples/placeholder/extension.ts deleted file mode 100644 index 12d0ba26f4..0000000000 --- a/react-placeholder/src/components/editor/examples/placeholder/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Type something...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-placeholder/src/components/editor/examples/placeholder/index.ts b/react-placeholder/src/components/editor/examples/placeholder/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-placeholder/src/components/editor/examples/placeholder/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-placeholder/src/main.tsx b/react-placeholder/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-placeholder/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-placeholder/tsconfig.app.json b/react-placeholder/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-placeholder/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-placeholder/tsconfig.json b/react-placeholder/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-placeholder/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-placeholder/tsconfig.node.json b/react-placeholder/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-placeholder/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-placeholder/vite.config.ts b/react-placeholder/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-placeholder/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-readonly/.gitignore b/react-readonly/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-readonly/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-readonly/README.md b/react-readonly/README.md deleted file mode 100644 index 272e1ce1bc..0000000000 --- a/react-readonly/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-readonly - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-readonly) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-readonly) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-readonly react-readonly -cd react-readonly -npm install -npm run dev -``` diff --git a/react-readonly/index.html b/react-readonly/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-readonly/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-readonly/package.json b/react-readonly/package.json deleted file mode 100644 index d615980017..0000000000 --- a/react-readonly/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-readonly", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-readonly/src/App.tsx b/react-readonly/src/App.tsx deleted file mode 100644 index dc728e840f..0000000000 --- a/react-readonly/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/readonly' - -export default function App() { - return -} diff --git a/react-readonly/src/app.css b/react-readonly/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-readonly/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-readonly/src/components/editor/examples/readonly/editor.tsx b/react-readonly/src/components/editor/examples/readonly/editor.tsx deleted file mode 100644 index 195084fd14..0000000000 --- a/react-readonly/src/components/editor/examples/readonly/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-readonly' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-readonly/src/components/editor/examples/readonly/extension.ts b/react-readonly/src/components/editor/examples/readonly/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/react-readonly/src/components/editor/examples/readonly/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/react-readonly/src/components/editor/examples/readonly/index.ts b/react-readonly/src/components/editor/examples/readonly/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-readonly/src/components/editor/examples/readonly/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-readonly/src/components/editor/examples/readonly/toolbar.tsx b/react-readonly/src/components/editor/examples/readonly/toolbar.tsx deleted file mode 100644 index 4321339858..0000000000 --- a/react-readonly/src/components/editor/examples/readonly/toolbar.tsx +++ /dev/null @@ -1,21 +0,0 @@ -'use client' - -import { Button } from '../../ui/button' - -import { useReadonly } from './use-readonly' - -export default function Toolbar() { - const { readonly, setReadonly } = useReadonly() - - return ( -
- - - -
- ) -} diff --git a/react-readonly/src/components/editor/examples/readonly/use-readonly.ts b/react-readonly/src/components/editor/examples/readonly/use-readonly.ts deleted file mode 100644 index 90699e2168..0000000000 --- a/react-readonly/src/components/editor/examples/readonly/use-readonly.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineReadonly } from 'prosekit/extensions/readonly' -import { useExtension } from 'prosekit/react' -import { useMemo, useState } from 'react' - -export function useReadonly() { - const [readonly, setReadonly] = useState(true) - - const extension = useMemo(() => { - return readonly ? defineReadonly() : null - }, [readonly]) - useExtension(extension) - - return { readonly, setReadonly } -} diff --git a/react-readonly/src/components/editor/sample/sample-doc-readonly.ts b/react-readonly/src/components/editor/sample/sample-doc-readonly.ts deleted file mode 100644 index abd9e2c6ac..0000000000 --- a/react-readonly/src/components/editor/sample/sample-doc-readonly.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', - }, - ], - }, - ], -} diff --git a/react-readonly/src/components/editor/ui/button/button.tsx b/react-readonly/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-readonly/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-readonly/src/components/editor/ui/button/index.ts b/react-readonly/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-readonly/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-readonly/src/main.tsx b/react-readonly/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-readonly/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-readonly/tsconfig.app.json b/react-readonly/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-readonly/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-readonly/tsconfig.json b/react-readonly/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-readonly/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-readonly/tsconfig.node.json b/react-readonly/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-readonly/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-readonly/vite.config.ts b/react-readonly/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-readonly/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-rtl/.gitignore b/react-rtl/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-rtl/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-rtl/README.md b/react-rtl/README.md deleted file mode 100644 index 40016e9cca..0000000000 --- a/react-rtl/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-rtl - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-rtl) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-rtl) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-rtl react-rtl -cd react-rtl -npm install -npm run dev -``` diff --git a/react-rtl/index.html b/react-rtl/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-rtl/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-rtl/package.json b/react-rtl/package.json deleted file mode 100644 index a5d2861c4c..0000000000 --- a/react-rtl/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-rtl", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-rtl/src/App.tsx b/react-rtl/src/App.tsx deleted file mode 100644 index b7c8653ece..0000000000 --- a/react-rtl/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/rtl' - -export default function App() { - return -} diff --git a/react-rtl/src/app.css b/react-rtl/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-rtl/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-rtl/src/components/editor/examples/rtl/editor.tsx b/react-rtl/src/components/editor/examples/rtl/editor.tsx deleted file mode 100644 index 186955c590..0000000000 --- a/react-rtl/src/components/editor/examples/rtl/editor.tsx +++ /dev/null @@ -1,52 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-rtl' -import { sampleUploader } from '../../sample/sample-uploader' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' -import { InlineMenu } from '../../ui/inline-menu' -import { SlashMenu } from '../../ui/slash-menu' -import { TableHandle } from '../../ui/table-handle' -import { Toolbar } from '../../ui/toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
- - - - - -
-
-
- ) -} diff --git a/react-rtl/src/components/editor/examples/rtl/index.ts b/react-rtl/src/components/editor/examples/rtl/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-rtl/src/components/editor/examples/rtl/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-rtl/src/components/editor/sample/sample-doc-rtl.ts b/react-rtl/src/components/editor/sample/sample-doc-rtl.ts deleted file mode 100644 index 696e797724..0000000000 --- a/react-rtl/src/components/editor/sample/sample-doc-rtl.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const translation = { - Paragraph: 'فقرة', - 'Root list item': 'عنصر قائمة جذري', - 'Sub list item': 'عنصر قائمة فرعي', - 'Completed task': 'مهمة مكتملة', - 'Pending task': 'مهمة قيد الانتظار', - Quote: 'اقتباس', -} as const - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Right to Left' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Paragraph'] }], - }, - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Root list item'] }], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Completed task'] }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Pending task'] }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: 'hello world', - }, - ], - }, - - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, - ], - }, - ], - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: translation['Quote'], - }, - ], - }, - ], - }, - ], -} diff --git a/react-rtl/src/components/editor/sample/sample-uploader.ts b/react-rtl/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/react-rtl/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/react-rtl/src/components/editor/ui/block-handle/block-handle.tsx b/react-rtl/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 3cc6028d5c..0000000000 --- a/react-rtl/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' - -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/react/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/react-rtl/src/components/editor/ui/block-handle/index.ts b/react-rtl/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/react-rtl/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/react-rtl/src/components/editor/ui/button/button.tsx b/react-rtl/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-rtl/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-rtl/src/components/editor/ui/button/index.ts b/react-rtl/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-rtl/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/react-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx deleted file mode 100644 index 87c1746622..0000000000 --- a/react-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx +++ /dev/null @@ -1,7 +0,0 @@ -'use client' - -import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator' - -export default function DropIndicator() { - return -} diff --git a/react-rtl/src/components/editor/ui/drop-indicator/index.ts b/react-rtl/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index f8fb7139c4..0000000000 --- a/react-rtl/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator' diff --git a/react-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-rtl/src/components/editor/ui/image-upload-popover/index.ts b/react-rtl/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-rtl/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-rtl/src/components/editor/ui/inline-menu/index.ts b/react-rtl/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/react-rtl/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/react-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index af1b2bb2b7..0000000000 --- a/react-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/react' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/react/inline-popover' -import { useState } from 'react' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/react-rtl/src/components/editor/ui/slash-menu/index.ts b/react-rtl/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/react-rtl/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/react-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/react-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index d0dca0934a..0000000000 --- a/react-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,11 +0,0 @@ -'use client' - -import { AutocompleteEmpty } from 'prosekit/react/autocomplete' - -export default function SlashMenuEmpty() { - return ( - - No results - - ) -} diff --git a/react-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/react-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 349c6e8924..0000000000 --- a/react-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client' - -import { AutocompleteItem } from 'prosekit/react/autocomplete' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}) { - return ( - - {props.label} - {props.kbd && ( - - {props.kbd} - - )} - - ) -} diff --git a/react-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx b/react-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index 3738f51aab..0000000000 --- a/react-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,102 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/react' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor.commands.setParagraph()} - /> - - editor.commands.setHeading({ level: 1 })} - /> - - editor.commands.setHeading({ level: 2 })} - /> - - editor.commands.setHeading({ level: 3 })} - /> - - editor.commands.wrapInList({ kind: 'bullet' })} - /> - - editor.commands.wrapInList({ kind: 'ordered' })} - /> - - editor.commands.wrapInList({ kind: 'task' })} - /> - - editor.commands.wrapInList({ kind: 'toggle' })} - /> - - editor.commands.setBlockquote()} - /> - - editor.commands.insertTable({ row: 3, col: 3 })} - /> - - editor.commands.insertHorizontalRule()} - /> - - editor.commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/react-rtl/src/components/editor/ui/table-handle/index.ts b/react-rtl/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/react-rtl/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/react-rtl/src/components/editor/ui/table-handle/table-handle.tsx b/react-rtl/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index b90b351382..0000000000 --- a/react-rtl/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,188 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/react' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/react/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/react/table-handle' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props) { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - {state.addTableColumnBefore.canExec && ( - - Insert Left - - )} - {state.addTableColumnAfter.canExec && ( - - Insert Right - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableColumn.canExec && ( - - Delete Column - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
- - - - -
-
- - - {state.addTableRowAbove.canExec && ( - - Insert Above - - )} - {state.addTableRowBelow.canExec && ( - - Insert Below - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableRow.canExec && ( - - Delete Row - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
-
- ) -} diff --git a/react-rtl/src/components/editor/ui/toolbar/index.ts b/react-rtl/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-rtl/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-rtl/src/components/editor/ui/toolbar/toolbar.tsx b/react-rtl/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-rtl/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-rtl/src/main.tsx b/react-rtl/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-rtl/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-rtl/tsconfig.app.json b/react-rtl/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-rtl/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-rtl/tsconfig.json b/react-rtl/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-rtl/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-rtl/tsconfig.node.json b/react-rtl/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-rtl/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-rtl/vite.config.ts b/react-rtl/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-rtl/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-save-html/.gitignore b/react-save-html/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-save-html/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-save-html/README.md b/react-save-html/README.md deleted file mode 100644 index 4be15ecaff..0000000000 --- a/react-save-html/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-save-html - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-save-html) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-save-html) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-save-html react-save-html -cd react-save-html -npm install -npm run dev -``` diff --git a/react-save-html/index.html b/react-save-html/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-save-html/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-save-html/package.json b/react-save-html/package.json deleted file mode 100644 index 91bd766538..0000000000 --- a/react-save-html/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-save-html", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-save-html/src/App.tsx b/react-save-html/src/App.tsx deleted file mode 100644 index cd1a678bb6..0000000000 --- a/react-save-html/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-html' - -export default function App() { - return -} diff --git a/react-save-html/src/app.css b/react-save-html/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-save-html/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-save-html/src/components/editor/examples/save-html/editor.tsx b/react-save-html/src/components/editor/examples/save-html/editor.tsx deleted file mode 100644 index 0b0dd123d5..0000000000 --- a/react-save-html/src/components/editor/examples/save-html/editor.tsx +++ /dev/null @@ -1,76 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, jsonFromHTML } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/react' -import { useCallback, useMemo, useState } from 'react' - -export default function Editor() { - // A list of saved documents, stored as HTML strings - const [records, setRecords] = useState([]) - // Whether there are unsaved changes - const [hasUnsavedChange, setHasUnsavedChange] = useState(false) - // A key to force a re-render of the editor - const [key, setKey] = useState(1) - - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension }) - }, []) - - const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) - useDocChange(handleDocChange, { editor }) - - const handleSave = useCallback(() => { - const record = editor.getDocHTML() - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - }, [editor]) - - const handleLoad = useCallback( - (record: string) => { - editor.setContent(jsonFromHTML(record, { schema: editor.schema })) - setHasUnsavedChange(false) - setKey((prev) => prev + 1) - }, - [editor], - ) - - return ( -
- -
    - {records.map((record, index) => ( -
  • - - -
    {record}
    -
    -
  • - ))} -
- -
-
-
-
-
- ) -} diff --git a/react-save-html/src/components/editor/examples/save-html/index.ts b/react-save-html/src/components/editor/examples/save-html/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-save-html/src/components/editor/examples/save-html/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-save-html/src/main.tsx b/react-save-html/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-save-html/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-save-html/tsconfig.app.json b/react-save-html/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-save-html/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-save-html/tsconfig.json b/react-save-html/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-save-html/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-save-html/tsconfig.node.json b/react-save-html/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-save-html/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-save-html/vite.config.ts b/react-save-html/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-save-html/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-save-json/.gitignore b/react-save-json/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-save-json/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-save-json/README.md b/react-save-json/README.md deleted file mode 100644 index 6f336a1553..0000000000 --- a/react-save-json/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-save-json - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-save-json) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-save-json) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-save-json react-save-json -cd react-save-json -npm install -npm run dev -``` diff --git a/react-save-json/index.html b/react-save-json/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-save-json/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-save-json/package.json b/react-save-json/package.json deleted file mode 100644 index 2516e6babf..0000000000 --- a/react-save-json/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-save-json", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-save-json/src/App.tsx b/react-save-json/src/App.tsx deleted file mode 100644 index c35583f0b4..0000000000 --- a/react-save-json/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-json' - -export default function App() { - return -} diff --git a/react-save-json/src/app.css b/react-save-json/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-save-json/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-save-json/src/components/editor/examples/save-json/editor.tsx b/react-save-json/src/components/editor/examples/save-json/editor.tsx deleted file mode 100644 index 74c44bbb98..0000000000 --- a/react-save-json/src/components/editor/examples/save-json/editor.tsx +++ /dev/null @@ -1,76 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/react' -import { useCallback, useMemo, useState } from 'react' - -export default function Editor() { - // A list of saved documents, stored as JSON strings - const [records, setRecords] = useState([]) - // Whether there are unsaved changes - const [hasUnsavedChange, setHasUnsavedChange] = useState(false) - // A key to force a re-render of the editor - const [key, setKey] = useState(1) - - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension }) - }, []) - - const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) - useDocChange(handleDocChange, { editor }) - - const handleSave = useCallback(() => { - const record = JSON.stringify(editor.getDocJSON()) - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - }, [editor]) - - const handleLoad = useCallback( - (record: string) => { - editor.setContent(JSON.parse(record) as NodeJSON) - setHasUnsavedChange(false) - setKey((prev) => prev + 1) - }, - [editor], - ) - - return ( -
- -
    - {records.map((record, index) => ( -
  • - - -
    {record}
    -
    -
  • - ))} -
- -
-
-
-
-
- ) -} diff --git a/react-save-json/src/components/editor/examples/save-json/index.ts b/react-save-json/src/components/editor/examples/save-json/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-save-json/src/components/editor/examples/save-json/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-save-json/src/main.tsx b/react-save-json/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-save-json/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-save-json/tsconfig.app.json b/react-save-json/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-save-json/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-save-json/tsconfig.json b/react-save-json/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-save-json/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-save-json/tsconfig.node.json b/react-save-json/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-save-json/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-save-json/vite.config.ts b/react-save-json/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-save-json/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-save-markdown/.gitignore b/react-save-markdown/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-save-markdown/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-save-markdown/README.md b/react-save-markdown/README.md deleted file mode 100644 index 4964905102..0000000000 --- a/react-save-markdown/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-save-markdown - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-save-markdown) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-save-markdown) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-save-markdown react-save-markdown -cd react-save-markdown -npm install -npm run dev -``` diff --git a/react-save-markdown/index.html b/react-save-markdown/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-save-markdown/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-save-markdown/package.json b/react-save-markdown/package.json deleted file mode 100644 index 5749c9e7ad..0000000000 --- a/react-save-markdown/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "example-react-save-markdown", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6", - "rehype-parse": "^9.0.1", - "rehype-remark": "^10.0.1", - "remark-gfm": "^4.0.1", - "remark-html": "^16.0.1", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.5" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-save-markdown/src/App.tsx b/react-save-markdown/src/App.tsx deleted file mode 100644 index 776d1fdf5b..0000000000 --- a/react-save-markdown/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-markdown' - -export default function App() { - return -} diff --git a/react-save-markdown/src/app.css b/react-save-markdown/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-save-markdown/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-save-markdown/src/components/editor/examples/save-markdown/editor.tsx b/react-save-markdown/src/components/editor/examples/save-markdown/editor.tsx deleted file mode 100644 index bcfe0d9724..0000000000 --- a/react-save-markdown/src/components/editor/examples/save-markdown/editor.tsx +++ /dev/null @@ -1,80 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, jsonFromHTML } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/react' -import { useCallback, useMemo, useState } from 'react' - -import { htmlFromMarkdown, markdownFromHTML } from './markdown' - -export default function Editor() { - // A list of saved documents, stored as Markdown strings - const [records, setRecords] = useState([]) - // Whether there are unsaved changes - const [hasUnsavedChange, setHasUnsavedChange] = useState(false) - // A key to force a re-render of the editor - const [key, setKey] = useState(1) - - const editor = useMemo(() => { - const extension = defineBasicExtension() - return createEditor({ extension }) - }, []) - - const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) - useDocChange(handleDocChange, { editor }) - - const handleSave = useCallback(() => { - const html = editor.getDocHTML() - const record = markdownFromHTML(html) - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - }, [editor]) - - const handleLoad = useCallback( - (record: string) => { - const html = htmlFromMarkdown(record) - editor.setContent(jsonFromHTML(html, { schema: editor.schema })) - setHasUnsavedChange(false) - setKey((prev) => prev + 1) - }, - [editor], - ) - - return ( -
- -
    - {records.map((record, index) => ( -
  • - - -
    {record}
    -
    -
  • - ))} -
- -
-
-
-
-
- ) -} diff --git a/react-save-markdown/src/components/editor/examples/save-markdown/index.ts b/react-save-markdown/src/components/editor/examples/save-markdown/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-save-markdown/src/components/editor/examples/save-markdown/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/react-save-markdown/src/components/editor/examples/save-markdown/markdown.ts deleted file mode 100644 index 3f930adad2..0000000000 --- a/react-save-markdown/src/components/editor/examples/save-markdown/markdown.ts +++ /dev/null @@ -1,26 +0,0 @@ -import rehypeParse from 'rehype-parse' -import rehypeRemark from 'rehype-remark' -import remarkGfm from 'remark-gfm' -import remarkHtml from 'remark-html' -import remarkParse from 'remark-parse' -import remarkStringify from 'remark-stringify' -import { unified } from 'unified' - -export function markdownFromHTML(html: string): string { - return unified() - .use(rehypeParse) - .use(rehypeRemark) - .use(remarkGfm) - .use(remarkStringify) - .processSync(html) - .toString() -} - -export function htmlFromMarkdown(markdown: string): string { - return unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkHtml) - .processSync(markdown) - .toString() -} diff --git a/react-save-markdown/src/main.tsx b/react-save-markdown/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-save-markdown/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-save-markdown/tsconfig.app.json b/react-save-markdown/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-save-markdown/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-save-markdown/tsconfig.json b/react-save-markdown/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-save-markdown/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-save-markdown/tsconfig.node.json b/react-save-markdown/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-save-markdown/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-save-markdown/vite.config.ts b/react-save-markdown/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-save-markdown/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-search/.gitignore b/react-search/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-search/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-search/README.md b/react-search/README.md deleted file mode 100644 index 48cd70bb95..0000000000 --- a/react-search/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-search - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-search) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-search) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-search react-search -cd react-search -npm install -npm run dev -``` diff --git a/react-search/index.html b/react-search/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-search/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-search/package.json b/react-search/package.json deleted file mode 100644 index b61ebebc32..0000000000 --- a/react-search/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-search", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-search/src/App.tsx b/react-search/src/App.tsx deleted file mode 100644 index 2f6b77056f..0000000000 --- a/react-search/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/search' - -export default function App() { - return -} diff --git a/react-search/src/app.css b/react-search/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-search/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-search/src/components/editor/examples/search/editor.tsx b/react-search/src/components/editor/examples/search/editor.tsx deleted file mode 100644 index 6f5d80b394..0000000000 --- a/react-search/src/components/editor/examples/search/editor.tsx +++ /dev/null @@ -1,43 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/search/style.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-search' -import { Search } from '../../ui/search' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ - extension, - defaultContent, - }) - }, [defaultContent]) - - return ( - -
-
- -
-
-
-
- ) -} diff --git a/react-search/src/components/editor/examples/search/extension.ts b/react-search/src/components/editor/examples/search/extension.ts deleted file mode 100644 index 10ff13f614..0000000000 --- a/react-search/src/components/editor/examples/search/extension.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineSearchCommands } from 'prosekit/extensions/search' - -export function defineExtension() { - return union(defineBasicExtension(), defineSearchCommands()) -} - -export type EditorExtension = ReturnType diff --git a/react-search/src/components/editor/examples/search/index.ts b/react-search/src/components/editor/examples/search/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-search/src/components/editor/examples/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-search/src/components/editor/sample/sample-doc-search.ts b/react-search/src/components/editor/sample/sample-doc-search.ts deleted file mode 100644 index c8160cca2a..0000000000 --- a/react-search/src/components/editor/sample/sample-doc-search.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Baa, baa, black sheep,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Have you any wool?', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Yes, sir, yes, sir,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Three bags full;', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'One for the master,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the dame,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the little boy', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Who lives down the lane.', - }, - ], - }, - ], -} diff --git a/react-search/src/components/editor/ui/button/button.tsx b/react-search/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-search/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-search/src/components/editor/ui/button/index.ts b/react-search/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-search/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-search/src/components/editor/ui/search/index.ts b/react-search/src/components/editor/ui/search/index.ts deleted file mode 100644 index 0a1f03c720..0000000000 --- a/react-search/src/components/editor/ui/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Search } from './search' diff --git a/react-search/src/components/editor/ui/search/search.tsx b/react-search/src/components/editor/ui/search/search.tsx deleted file mode 100644 index 2ab70ee512..0000000000 --- a/react-search/src/components/editor/ui/search/search.tsx +++ /dev/null @@ -1,169 +0,0 @@ -'use client' - -import { - defineSearchQuery, - type SearchCommandsExtension, -} from 'prosekit/extensions/search' -import { useEditor, useExtension } from 'prosekit/react' -import { useMemo, useState } from 'react' - -import { Button } from '../button' - -export default function Search(props: { onClose?: VoidFunction }) { - const [showReplace, setShowReplace] = useState(false) - const toggleReplace = () => setShowReplace((value) => !value) - - const [searchText, setSearchText] = useState('') - const [replaceText, setReplaceText] = useState('') - const [caseSensitive, setCaseSensitive] = useState(false) - const [wholeWord, setWholeWord] = useState(false) - const [regexp, setRegexp] = useState(false) - const [literal, setLiteral] = useState(false) - - const extension = useMemo(() => { - if (!searchText) { - return null - } - return defineSearchQuery({ - search: searchText, - replace: replaceText, - caseSensitive, - wholeWord, - regexp, - literal, - }) - }, [searchText, replaceText, caseSensitive, wholeWord, regexp, literal]) - - useExtension(extension) - - const editor = useEditor() - - const handleSearchKeyDown = (event: React.KeyboardEvent) => { - if (isEnter(event)) { - event.preventDefault() - editor.commands.findNext() - } else if (isShiftEnter(event)) { - event.preventDefault() - editor.commands.findPrev() - } - } - - const handleReplaceKeyDown = (event: React.KeyboardEvent) => { - if (isEnter(event)) { - event.preventDefault() - editor.commands.replaceNext() - } else if (isShiftEnter(event)) { - event.preventDefault() - editor.commands.replaceAll() - } - } - - return ( -
- - setSearchText(event.target.value)} - onKeyDown={handleSearchKeyDown} - className="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" - /> -
- - - - - - - -
- {showReplace && ( - setReplaceText(event.target.value)} - onKeyDown={handleReplaceKeyDown} - className="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" - /> - )} - {showReplace && ( -
- - -
- )} -
- ) -} - -function isEnter(event: React.KeyboardEvent) { - return ( - event.key === 'Enter' && - !event.shiftKey && - !event.metaKey && - !event.altKey && - !event.ctrlKey && - !event.nativeEvent.isComposing - ) -} - -function isShiftEnter(event: React.KeyboardEvent) { - return ( - event.key === 'Enter' && - event.shiftKey && - !event.metaKey && - !event.altKey && - !event.ctrlKey && - !event.nativeEvent.isComposing - ) -} diff --git a/react-search/src/main.tsx b/react-search/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-search/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-search/tsconfig.app.json b/react-search/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-search/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-search/tsconfig.json b/react-search/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-search/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-search/tsconfig.node.json b/react-search/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-search/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-search/vite.config.ts b/react-search/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-search/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-slash-menu/.gitignore b/react-slash-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-slash-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-slash-menu/README.md b/react-slash-menu/README.md deleted file mode 100644 index 83a24da4b0..0000000000 --- a/react-slash-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-slash-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-slash-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-slash-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-slash-menu react-slash-menu -cd react-slash-menu -npm install -npm run dev -``` diff --git a/react-slash-menu/index.html b/react-slash-menu/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-slash-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-slash-menu/package.json b/react-slash-menu/package.json deleted file mode 100644 index 7e4b496ddf..0000000000 --- a/react-slash-menu/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-slash-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-slash-menu/src/App.tsx b/react-slash-menu/src/App.tsx deleted file mode 100644 index cf430661be..0000000000 --- a/react-slash-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/slash-menu' - -export default function App() { - return -} diff --git a/react-slash-menu/src/app.css b/react-slash-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-slash-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-slash-menu/src/components/editor/examples/slash-menu/editor.tsx b/react-slash-menu/src/components/editor/examples/slash-menu/editor.tsx deleted file mode 100644 index b89d418a89..0000000000 --- a/react-slash-menu/src/components/editor/examples/slash-menu/editor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { SlashMenu } from '../../ui/slash-menu' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/react-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/react-slash-menu/src/components/editor/examples/slash-menu/extension.ts deleted file mode 100644 index 0edda60136..0000000000 --- a/react-slash-menu/src/components/editor/examples/slash-menu/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-slash-menu/src/components/editor/examples/slash-menu/index.ts b/react-slash-menu/src/components/editor/examples/slash-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-slash-menu/src/components/editor/examples/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-slash-menu/src/components/editor/ui/slash-menu/index.ts b/react-slash-menu/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/react-slash-menu/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index d0dca0934a..0000000000 --- a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,11 +0,0 @@ -'use client' - -import { AutocompleteEmpty } from 'prosekit/react/autocomplete' - -export default function SlashMenuEmpty() { - return ( - - No results - - ) -} diff --git a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 349c6e8924..0000000000 --- a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client' - -import { AutocompleteItem } from 'prosekit/react/autocomplete' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}) { - return ( - - {props.label} - {props.kbd && ( - - {props.kbd} - - )} - - ) -} diff --git a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index 3738f51aab..0000000000 --- a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,102 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/react' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor.commands.setParagraph()} - /> - - editor.commands.setHeading({ level: 1 })} - /> - - editor.commands.setHeading({ level: 2 })} - /> - - editor.commands.setHeading({ level: 3 })} - /> - - editor.commands.wrapInList({ kind: 'bullet' })} - /> - - editor.commands.wrapInList({ kind: 'ordered' })} - /> - - editor.commands.wrapInList({ kind: 'task' })} - /> - - editor.commands.wrapInList({ kind: 'toggle' })} - /> - - editor.commands.setBlockquote()} - /> - - editor.commands.insertTable({ row: 3, col: 3 })} - /> - - editor.commands.insertHorizontalRule()} - /> - - editor.commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/react-slash-menu/src/main.tsx b/react-slash-menu/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-slash-menu/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-slash-menu/tsconfig.app.json b/react-slash-menu/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-slash-menu/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-slash-menu/tsconfig.json b/react-slash-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-slash-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-slash-menu/tsconfig.node.json b/react-slash-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-slash-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-slash-menu/vite.config.ts b/react-slash-menu/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-slash-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-strike/.gitignore b/react-strike/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-strike/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-strike/README.md b/react-strike/README.md deleted file mode 100644 index ded25bd4bd..0000000000 --- a/react-strike/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-strike - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-strike) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-strike) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-strike react-strike -cd react-strike -npm install -npm run dev -``` diff --git a/react-strike/index.html b/react-strike/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-strike/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-strike/package.json b/react-strike/package.json deleted file mode 100644 index 09c9528605..0000000000 --- a/react-strike/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-strike", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-strike/src/App.tsx b/react-strike/src/App.tsx deleted file mode 100644 index 497a57c0d8..0000000000 --- a/react-strike/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/strike' - -export default function App() { - return -} diff --git a/react-strike/src/app.css b/react-strike/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-strike/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-strike/src/components/editor/examples/strike/editor.tsx b/react-strike/src/components/editor/examples/strike/editor.tsx deleted file mode 100644 index f3378a871d..0000000000 --- a/react-strike/src/components/editor/examples/strike/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-strike' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-strike/src/components/editor/examples/strike/extension.ts b/react-strike/src/components/editor/examples/strike/extension.ts deleted file mode 100644 index c013303ccc..0000000000 --- a/react-strike/src/components/editor/examples/strike/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineStrike(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-strike/src/components/editor/examples/strike/index.ts b/react-strike/src/components/editor/examples/strike/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-strike/src/components/editor/examples/strike/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-strike/src/components/editor/examples/strike/toolbar.tsx b/react-strike/src/components/editor/examples/strike/toolbar.tsx deleted file mode 100644 index 67b359dd17..0000000000 --- a/react-strike/src/components/editor/examples/strike/toolbar.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - strike: { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/react-strike/src/components/editor/sample/sample-doc-strike.ts b/react-strike/src/components/editor/sample/sample-doc-strike.ts deleted file mode 100644 index 2e025e9b02..0000000000 --- a/react-strike/src/components/editor/sample/sample-doc-strike.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'This is strike', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/react-strike/src/components/editor/ui/button/button.tsx b/react-strike/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-strike/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-strike/src/components/editor/ui/button/index.ts b/react-strike/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-strike/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-strike/src/main.tsx b/react-strike/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-strike/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-strike/tsconfig.app.json b/react-strike/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-strike/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-strike/tsconfig.json b/react-strike/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-strike/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-strike/tsconfig.node.json b/react-strike/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-strike/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-strike/vite.config.ts b/react-strike/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-strike/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-sub-sup/.gitignore b/react-sub-sup/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-sub-sup/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-sub-sup/README.md b/react-sub-sup/README.md deleted file mode 100644 index 02b78e8e1e..0000000000 --- a/react-sub-sup/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-sub-sup - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-sub-sup) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-sub-sup) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-sub-sup react-sub-sup -cd react-sub-sup -npm install -npm run dev -``` diff --git a/react-sub-sup/index.html b/react-sub-sup/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-sub-sup/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-sub-sup/package.json b/react-sub-sup/package.json deleted file mode 100644 index 04d6014a0a..0000000000 --- a/react-sub-sup/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-sub-sup", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-sub-sup/src/App.tsx b/react-sub-sup/src/App.tsx deleted file mode 100644 index 48e43d6423..0000000000 --- a/react-sub-sup/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/sub-sup' - -export default function App() { - return -} diff --git a/react-sub-sup/src/app.css b/react-sub-sup/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-sub-sup/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-sub-sup/src/components/editor/examples/sub-sup/editor.tsx b/react-sub-sup/src/components/editor/examples/sub-sup/editor.tsx deleted file mode 100644 index 43a765e067..0000000000 --- a/react-sub-sup/src/components/editor/examples/sub-sup/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-sub-sup' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/react-sub-sup/src/components/editor/examples/sub-sup/extension.ts deleted file mode 100644 index bd67245f86..0000000000 --- a/react-sub-sup/src/components/editor/examples/sub-sup/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineMarkInputRule } from 'prosekit/extensions/input-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineSubscript } from 'prosekit/extensions/subscript' -import { defineSuperscript } from 'prosekit/extensions/superscript' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineSubscript(), - defineSuperscript(), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ - : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, - type: 'subscript', - }), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ - : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, - type: 'superscript', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-sub-sup/src/components/editor/examples/sub-sup/index.ts b/react-sub-sup/src/components/editor/examples/sub-sup/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-sub-sup/src/components/editor/examples/sub-sup/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx b/react-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx deleted file mode 100644 index 7a22c8d073..0000000000 --- a/react-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - subscript: { - isActive: editor.marks.subscript.isActive(), - canExec: editor.commands.toggleSubscript.canExec(), - command: () => editor.commands.toggleSubscript(), - }, - superscript: { - isActive: editor.marks.superscript.isActive(), - canExec: editor.commands.toggleSuperscript.canExec(), - command: () => editor.commands.toggleSuperscript(), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - -
- ) -} diff --git a/react-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/react-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts deleted file mode 100644 index 011be750dc..0000000000 --- a/react-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'H', - }, - { - type: 'text', - marks: [ - { - type: 'subscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: 'O is water. x', - }, - { - type: 'text', - marks: [ - { - type: 'superscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: ' is a square.', - }, - ], - }, - ], -} diff --git a/react-sub-sup/src/components/editor/ui/button/button.tsx b/react-sub-sup/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-sub-sup/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-sub-sup/src/components/editor/ui/button/index.ts b/react-sub-sup/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-sub-sup/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-sub-sup/src/main.tsx b/react-sub-sup/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-sub-sup/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-sub-sup/tsconfig.app.json b/react-sub-sup/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-sub-sup/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-sub-sup/tsconfig.json b/react-sub-sup/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-sub-sup/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-sub-sup/tsconfig.node.json b/react-sub-sup/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-sub-sup/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-sub-sup/vite.config.ts b/react-sub-sup/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-sub-sup/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-table/.gitignore b/react-table/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-table/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-table/README.md b/react-table/README.md deleted file mode 100644 index 82de244968..0000000000 --- a/react-table/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-table - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-table) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-table) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-table react-table -cd react-table -npm install -npm run dev -``` diff --git a/react-table/index.html b/react-table/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-table/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-table/package.json b/react-table/package.json deleted file mode 100644 index 733c44d828..0000000000 --- a/react-table/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-table", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-table/src/App.tsx b/react-table/src/App.tsx deleted file mode 100644 index 9d9d957adb..0000000000 --- a/react-table/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/table' - -export default function App() { - return -} diff --git a/react-table/src/app.css b/react-table/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-table/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-table/src/components/editor/examples/table/editor.tsx b/react-table/src/components/editor/examples/table/editor.tsx deleted file mode 100644 index fbd68b0859..0000000000 --- a/react-table/src/components/editor/examples/table/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-table' -import { TableHandle } from '../../ui/table-handle' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/react-table/src/components/editor/examples/table/extension.ts b/react-table/src/components/editor/examples/table/extension.ts deleted file mode 100644 index ee7b142041..0000000000 --- a/react-table/src/components/editor/examples/table/extension.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineTable(), - defineHistory(), - defineGapCursor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-table/src/components/editor/examples/table/index.ts b/react-table/src/components/editor/examples/table/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-table/src/components/editor/examples/table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-table/src/components/editor/sample/sample-doc-table.ts b/react-table/src/components/editor/sample/sample-doc-table.ts deleted file mode 100644 index c737121672..0000000000 --- a/react-table/src/components/editor/sample/sample-doc-table.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D1', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D2', - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], -} diff --git a/react-table/src/components/editor/ui/table-handle/index.ts b/react-table/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/react-table/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/react-table/src/components/editor/ui/table-handle/table-handle.tsx b/react-table/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index b90b351382..0000000000 --- a/react-table/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,188 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/react' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/react/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/react/table-handle' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props) { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - {state.addTableColumnBefore.canExec && ( - - Insert Left - - )} - {state.addTableColumnAfter.canExec && ( - - Insert Right - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableColumn.canExec && ( - - Delete Column - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
- - - - -
-
- - - {state.addTableRowAbove.canExec && ( - - Insert Above - - )} - {state.addTableRowBelow.canExec && ( - - Insert Below - - )} - {state.deleteCellSelection.canExec && ( - - Clear Contents - - Del - - - )} - {state.deleteTableRow.canExec && ( - - Delete Row - - )} - {state.deleteTable.canExec && ( - - Delete Table - - )} - - -
-
-
-
- ) -} diff --git a/react-table/src/main.tsx b/react-table/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-table/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-table/tsconfig.app.json b/react-table/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-table/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-table/tsconfig.json b/react-table/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-table/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-table/tsconfig.node.json b/react-table/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-table/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-table/vite.config.ts b/react-table/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-table/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-temml/.gitignore b/react-temml/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-temml/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-temml/README.md b/react-temml/README.md deleted file mode 100644 index 6caf95823f..0000000000 --- a/react-temml/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-temml - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-temml) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-temml) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-temml react-temml -cd react-temml -npm install -npm run dev -``` diff --git a/react-temml/index.html b/react-temml/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-temml/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-temml/package.json b/react-temml/package.json deleted file mode 100644 index a59556d381..0000000000 --- a/react-temml/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-react-temml", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6", - "temml": "^0.13.2" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-temml/src/App.tsx b/react-temml/src/App.tsx deleted file mode 100644 index f6ec50ec0e..0000000000 --- a/react-temml/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/temml' - -export default function App() { - return -} diff --git a/react-temml/src/app.css b/react-temml/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-temml/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-temml/src/components/editor/examples/temml/editor.tsx b/react-temml/src/components/editor/examples/temml/editor.tsx deleted file mode 100644 index 41d22fcbde..0000000000 --- a/react-temml/src/components/editor/examples/temml/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-tex' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/react-temml/src/components/editor/examples/temml/extension.ts b/react-temml/src/components/editor/examples/temml/extension.ts deleted file mode 100644 index 2fcd2ffa42..0000000000 --- a/react-temml/src/components/editor/examples/temml/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderTemmlMathBlock, renderTemmlMathInline } from '../../sample/temml' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderTemmlMathBlock, - renderMathInline: renderTemmlMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-temml/src/components/editor/examples/temml/index.ts b/react-temml/src/components/editor/examples/temml/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-temml/src/components/editor/examples/temml/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-temml/src/components/editor/sample/sample-doc-tex.ts b/react-temml/src/components/editor/sample/sample-doc-tex.ts deleted file mode 100644 index 21ccf3e94e..0000000000 --- a/react-temml/src/components/editor/sample/sample-doc-tex.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Inline equations' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Block equations' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: 'The Gaussian integral:' }], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - ], -} diff --git a/react-temml/src/components/editor/sample/temml.ts b/react-temml/src/components/editor/sample/temml.ts deleted file mode 100644 index 4cbe764f93..0000000000 --- a/react-temml/src/components/editor/sample/temml.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Temml from 'temml' - -export function renderTemmlMathBlock(text: string, element: HTMLElement) { - Temml.render(text, element, { - displayMode: true, - annotate: true, - throwOnError: false, - }) -} - -export function renderTemmlMathInline(text: string, element: HTMLElement) { - Temml.render(text, element, { - displayMode: false, - annotate: true, - throwOnError: false, - }) -} diff --git a/react-temml/src/main.tsx b/react-temml/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-temml/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-temml/tsconfig.app.json b/react-temml/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-temml/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-temml/tsconfig.json b/react-temml/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-temml/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-temml/tsconfig.node.json b/react-temml/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-temml/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-temml/vite.config.ts b/react-temml/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-temml/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-text-align/.gitignore b/react-text-align/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-text-align/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-text-align/README.md b/react-text-align/README.md deleted file mode 100644 index 73c219cf00..0000000000 --- a/react-text-align/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-text-align - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-text-align) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-text-align) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-text-align react-text-align -cd react-text-align -npm install -npm run dev -``` diff --git a/react-text-align/index.html b/react-text-align/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-text-align/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-text-align/package.json b/react-text-align/package.json deleted file mode 100644 index a63da1a323..0000000000 --- a/react-text-align/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-text-align", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-text-align/src/App.tsx b/react-text-align/src/App.tsx deleted file mode 100644 index 0c049df602..0000000000 --- a/react-text-align/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/text-align' - -export default function App() { - return -} diff --git a/react-text-align/src/app.css b/react-text-align/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-text-align/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-text-align/src/components/editor/examples/text-align/editor.tsx b/react-text-align/src/components/editor/examples/text-align/editor.tsx deleted file mode 100644 index bdfbfd031e..0000000000 --- a/react-text-align/src/components/editor/examples/text-align/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-text-align' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-text-align/src/components/editor/examples/text-align/extension.ts b/react-text-align/src/components/editor/examples/text-align/extension.ts deleted file mode 100644 index f1ae44dc7c..0000000000 --- a/react-text-align/src/components/editor/examples/text-align/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineTextAlign } from 'prosekit/extensions/text-align' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextAlign({ types: ['paragraph', 'heading'] }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-text-align/src/components/editor/examples/text-align/index.ts b/react-text-align/src/components/editor/examples/text-align/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-text-align/src/components/editor/examples/text-align/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-text-align/src/components/editor/examples/text-align/toolbar.tsx b/react-text-align/src/components/editor/examples/text-align/toolbar.tsx deleted file mode 100644 index b86702019a..0000000000 --- a/react-text-align/src/components/editor/examples/text-align/toolbar.tsx +++ /dev/null @@ -1,80 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function isTextAlignActive(editor: Editor, value: string) { - return Object.values(editor.nodes).some((node) => { - // @ts-expect-error textAlign may not be available on every node - return node.isActive({ textAlign: value }) - }) -} - -function getToolbarItems(editor: Editor) { - return { - left: { - isActive: isTextAlignActive(editor, 'left'), - canExec: editor.commands.setTextAlign.canExec('left'), - command: () => editor.commands.setTextAlign('left'), - }, - center: { - isActive: isTextAlignActive(editor, 'center'), - canExec: editor.commands.setTextAlign.canExec('center'), - command: () => editor.commands.setTextAlign('center'), - }, - right: { - isActive: isTextAlignActive(editor, 'right'), - canExec: editor.commands.setTextAlign.canExec('right'), - command: () => editor.commands.setTextAlign('right'), - }, - justify: { - isActive: isTextAlignActive(editor, 'justify'), - canExec: editor.commands.setTextAlign.canExec('justify'), - command: () => editor.commands.setTextAlign('justify'), - }, - } -} - -export default function Toolbar() { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - - - - - - -
- ) -} diff --git a/react-text-align/src/components/editor/sample/sample-doc-text-align.ts b/react-text-align/src/components/editor/sample/sample-doc-text-align.ts deleted file mode 100644 index 0724cea4f7..0000000000 --- a/react-text-align/src/components/editor/sample/sample-doc-text-align.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Heading', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'left', - }, - content: [ - { - type: 'text', - text: 'First paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Second paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'right', - }, - content: [ - { - type: 'text', - text: 'Third paragraph', - }, - ], - }, - ], -} diff --git a/react-text-align/src/components/editor/ui/button/button.tsx b/react-text-align/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-text-align/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-text-align/src/components/editor/ui/button/index.ts b/react-text-align/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-text-align/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-text-align/src/main.tsx b/react-text-align/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-text-align/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-text-align/tsconfig.app.json b/react-text-align/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-text-align/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-text-align/tsconfig.json b/react-text-align/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-text-align/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-text-align/tsconfig.node.json b/react-text-align/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-text-align/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-text-align/vite.config.ts b/react-text-align/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-text-align/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-text-color/.gitignore b/react-text-color/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-text-color/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-text-color/README.md b/react-text-color/README.md deleted file mode 100644 index bdf7d67828..0000000000 --- a/react-text-color/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-text-color - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-text-color) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-text-color) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-text-color react-text-color -cd react-text-color -npm install -npm run dev -``` diff --git a/react-text-color/index.html b/react-text-color/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-text-color/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-text-color/package.json b/react-text-color/package.json deleted file mode 100644 index 896f23f9c8..0000000000 --- a/react-text-color/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-text-color", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-text-color/src/App.tsx b/react-text-color/src/App.tsx deleted file mode 100644 index 1225de322a..0000000000 --- a/react-text-color/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/text-color' - -export default function App() { - return -} diff --git a/react-text-color/src/app.css b/react-text-color/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-text-color/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-text-color/src/components/editor/examples/text-color/editor.tsx b/react-text-color/src/components/editor/examples/text-color/editor.tsx deleted file mode 100644 index ce38555707..0000000000 --- a/react-text-color/src/components/editor/examples/text-color/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-text-color' - -import { defineExtension } from './extension' -import InlineMenu from './inline-menu' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/react-text-color/src/components/editor/examples/text-color/extension.ts b/react-text-color/src/components/editor/examples/text-color/extension.ts deleted file mode 100644 index d35d9d5c22..0000000000 --- a/react-text-color/src/components/editor/examples/text-color/extension.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineBackgroundColor } from 'prosekit/extensions/background-color' -import { defineTextColor } from 'prosekit/extensions/text-color' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextColor(), - defineBackgroundColor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-text-color/src/components/editor/examples/text-color/index.ts b/react-text-color/src/components/editor/examples/text-color/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-text-color/src/components/editor/examples/text-color/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-text-color/src/components/editor/examples/text-color/inline-menu.tsx b/react-text-color/src/components/editor/examples/text-color/inline-menu.tsx deleted file mode 100644 index 727551341c..0000000000 --- a/react-text-color/src/components/editor/examples/text-color/inline-menu.tsx +++ /dev/null @@ -1,147 +0,0 @@ -'use client' - -import type { Editor, Keymap } from 'prosekit/core' -import { useEditorDerivedValue, useKeymap } from 'prosekit/react' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/react/inline-popover' -import { useMemo, useState } from 'react' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -const textColors = [ - { label: 'Gray', value: '#9ca3af' }, - { label: 'Brown', value: '#92400e' }, - { label: 'Orange', value: '#ea580c' }, - { label: 'Yellow', value: '#ca8a04' }, - { label: 'Green', value: '#16a34a' }, - { label: 'Blue', value: '#2563eb' }, - { label: 'Purple', value: '#9333ea' }, - { label: 'Magenta', value: '#c026d3' }, - { label: 'Red', value: '#dc2626' }, -] - -const backgroundColors = [ - { label: 'Gray', value: '#f3f4f6' }, - { label: 'Brown', value: '#fef3c7' }, - { label: 'Orange', value: '#ffedd5' }, - { label: 'Yellow', value: '#fef9c3' }, - { label: 'Green', value: '#d1fae5' }, - { label: 'Blue', value: '#dbeafe' }, - { label: 'Purple', value: '#e9d5ff' }, - { label: 'Pink', value: '#fce7f3' }, - { label: 'Red', value: '#fecaca' }, -] - -function getTextColorState(editor: Editor) { - return [ - { - label: 'Default', - value: 'currentColor', - isActive: !editor.marks.textColor.isActive(), - onClick: () => editor.commands.removeTextColor(), - }, - ].concat( - textColors.map((color) => ({ - label: color.label, - value: color.value, - isActive: editor.marks.textColor.isActive({ color: color.value }), - onClick: () => editor.commands.addTextColor({ color: color.value }), - })), - ) -} - -function getBackgroundColorState(editor: Editor) { - return [ - { - label: 'Default', - value: 'canvas', - isActive: !editor.marks.backgroundColor.isActive(), - onClick: () => editor.commands.removeBackgroundColor(), - }, - ].concat( - backgroundColors.map((color) => ({ - label: color.label, - value: color.value, - isActive: editor.marks.backgroundColor.isActive({ color: color.value }), - onClick: () => editor.commands.addBackgroundColor({ color: color.value }), - })), - ) -} - -export default function InlineMenu() { - const textColorState = useEditorDerivedValue(getTextColorState) - const backgroundColorState = useEditorDerivedValue(getBackgroundColorState) - const [open, setOpen] = useState(false) - - const keymap: Keymap = useMemo( - () => ({ - Escape: () => { - if (open) { - setOpen(false) - return true - } - return false - }, - }), - [open], - ) - - useKeymap(keymap) - - return ( - setOpen(event.detail)} - > - - -
-
-
Text color
-
- {textColorState.map((color) => ( - - ))} -
-
-
-
Background color
-
- {backgroundColorState.map((color) => ( - - ))} -
-
-
-
-
-
- ) -} diff --git a/react-text-color/src/components/editor/sample/sample-doc-text-color.ts b/react-text-color/src/components/editor/sample/sample-doc-text-color.ts deleted file mode 100644 index a4efe4308d..0000000000 --- a/react-text-color/src/components/editor/sample/sample-doc-text-color.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#ef4444', - }, - }, - ], - text: 'Select', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#f97316', - }, - }, - ], - text: 'some', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#eab308', - }, - }, - ], - text: 'text', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#22c55e', - }, - }, - ], - text: 'to', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#3b82f6', - }, - }, - ], - text: 'change', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#6366f1', - }, - }, - ], - text: 'the', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#a855f7', - }, - }, - ], - text: 'color', - }, - ], - }, - ], -} diff --git a/react-text-color/src/components/editor/ui/button/button.tsx b/react-text-color/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-text-color/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-text-color/src/components/editor/ui/button/index.ts b/react-text-color/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-text-color/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-text-color/src/main.tsx b/react-text-color/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-text-color/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-text-color/tsconfig.app.json b/react-text-color/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-text-color/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-text-color/tsconfig.json b/react-text-color/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-text-color/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-text-color/tsconfig.node.json b/react-text-color/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-text-color/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-text-color/vite.config.ts b/react-text-color/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-text-color/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-toolbar/.gitignore b/react-toolbar/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-toolbar/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-toolbar/README.md b/react-toolbar/README.md deleted file mode 100644 index 7da35f4c31..0000000000 --- a/react-toolbar/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-toolbar - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-toolbar) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-toolbar) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-toolbar react-toolbar -cd react-toolbar -npm install -npm run dev -``` diff --git a/react-toolbar/index.html b/react-toolbar/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-toolbar/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-toolbar/package.json b/react-toolbar/package.json deleted file mode 100644 index 1ce0edaca4..0000000000 --- a/react-toolbar/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-toolbar", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-toolbar/src/App.tsx b/react-toolbar/src/App.tsx deleted file mode 100644 index 72699e4f11..0000000000 --- a/react-toolbar/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/toolbar' - -export default function App() { - return -} diff --git a/react-toolbar/src/app.css b/react-toolbar/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-toolbar/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-toolbar/src/components/editor/examples/toolbar/editor.tsx b/react-toolbar/src/components/editor/examples/toolbar/editor.tsx deleted file mode 100644 index d15dcd9ff4..0000000000 --- a/react-toolbar/src/components/editor/examples/toolbar/editor.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleUploader } from '../../sample/sample-uploader' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-toolbar/src/components/editor/examples/toolbar/extension.ts b/react-toolbar/src/components/editor/examples/toolbar/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/react-toolbar/src/components/editor/examples/toolbar/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/react-toolbar/src/components/editor/examples/toolbar/index.ts b/react-toolbar/src/components/editor/examples/toolbar/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-toolbar/src/components/editor/examples/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-toolbar/src/components/editor/sample/sample-uploader.ts b/react-toolbar/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/react-toolbar/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/react-toolbar/src/components/editor/ui/button/button.tsx b/react-toolbar/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-toolbar/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-toolbar/src/components/editor/ui/button/index.ts b/react-toolbar/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-toolbar/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/react-toolbar/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-toolbar/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-toolbar/src/components/editor/ui/toolbar/index.ts b/react-toolbar/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-toolbar/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-toolbar/src/components/editor/ui/toolbar/toolbar.tsx b/react-toolbar/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-toolbar/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-toolbar/src/main.tsx b/react-toolbar/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-toolbar/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-toolbar/tsconfig.app.json b/react-toolbar/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-toolbar/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-toolbar/tsconfig.json b/react-toolbar/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-toolbar/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-toolbar/tsconfig.node.json b/react-toolbar/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-toolbar/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-toolbar/vite.config.ts b/react-toolbar/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-toolbar/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-tweet/.gitignore b/react-tweet/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-tweet/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-tweet/README.md b/react-tweet/README.md deleted file mode 100644 index 93a6990cf6..0000000000 --- a/react-tweet/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-tweet - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-tweet) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-tweet) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-tweet react-tweet -cd react-tweet -npm install -npm run dev -``` diff --git a/react-tweet/index.html b/react-tweet/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-tweet/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-tweet/package.json b/react-tweet/package.json deleted file mode 100644 index 5f45222879..0000000000 --- a/react-tweet/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "example-react-tweet", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6", - "react-parallax-tilt": "^1.7.327", - "react-tweet": "^3.3.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-tweet/src/App.tsx b/react-tweet/src/App.tsx deleted file mode 100644 index f958ff180a..0000000000 --- a/react-tweet/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/tweet' - -export default function App() { - return -} diff --git a/react-tweet/src/app.css b/react-tweet/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-tweet/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-tweet/src/components/editor/examples/tweet/editor.tsx b/react-tweet/src/components/editor/examples/tweet/editor.tsx deleted file mode 100644 index a0a3a809a9..0000000000 --- a/react-tweet/src/components/editor/examples/tweet/editor.tsx +++ /dev/null @@ -1,53 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type Extension, type NodeJSON } from 'prosekit/core' -import { defineReactNodeView, ProseKit, useExtension } from 'prosekit/react' -import { useMemo, useState } from 'react' - -import { sampleContent } from '../../sample/sample-doc-tweet' - -import { defineExtension } from './extension' -import { MethodSelect } from './method-select' -import { TweetView } from './tweet-view' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - return createEditor({ extension: defineExtension(), defaultContent }) - }, [defaultContent]) - - const [method, setMethod] = useState<'basic' | 'advanced'>('basic') - - const reactTweetView: Extension | null = useMemo(() => { - if (method === 'basic') { - return null - } - return defineReactNodeView({ - name: 'tweet', - component: TweetView, - }) - }, [method]) - - useExtension(reactTweetView, { editor }) - - return ( - - -
-
-
-
-
-
- ) -} diff --git a/react-tweet/src/components/editor/examples/tweet/extension.ts b/react-tweet/src/components/editor/examples/tweet/extension.ts deleted file mode 100644 index ec730c0899..0000000000 --- a/react-tweet/src/components/editor/examples/tweet/extension.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { defineNodeSpec, union } from 'prosekit/core' - -function defineTweetSpec() { - return defineNodeSpec({ - name: 'tweet', - group: 'block', - attrs: { - tweetId: { default: null }, - }, - parseDOM: [ - { - tag: 'iframe[src^="https://platform.twitter.com/embed/Tweet.html"]', - getAttrs: (node) => { - const src = node.getAttribute('src') - const match = src?.match(/id=([^&]+)/) - return { - tweetId: match?.[1] ?? null, - } - }, - }, - ], - toDOM: (node) => { - return [ - 'iframe', - { - src: `https://platform.twitter.com/embed/Tweet.html?id=${node.attrs.tweetId}&theme=dark`, - style: 'height: 300px', - }, - ] - }, - }) -} - -function defineTweet() { - return union(defineTweetSpec()) -} - -export function defineExtension() { - return union(defineBasicExtension(), defineTweet()) -} - -export type EditorExtension = ReturnType diff --git a/react-tweet/src/components/editor/examples/tweet/index.ts b/react-tweet/src/components/editor/examples/tweet/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-tweet/src/components/editor/examples/tweet/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-tweet/src/components/editor/examples/tweet/method-select.tsx b/react-tweet/src/components/editor/examples/tweet/method-select.tsx deleted file mode 100644 index ceaf4cce13..0000000000 --- a/react-tweet/src/components/editor/examples/tweet/method-select.tsx +++ /dev/null @@ -1,42 +0,0 @@ -'use client' - -import { useId } from 'react' - -export function MethodSelect(props: { - value: 'basic' | 'advanced' - onChange: (value: 'basic' | 'advanced') => void -}) { - const id = 'id-' + useId() - const basicId = `${id}-basic` - const advancedId = `${id}-advanced` - - return ( -
- Select a render method: - -
- props.onChange('basic')} - /> - -
- -
- props.onChange('advanced')} - /> - -
-
- ) -} diff --git a/react-tweet/src/components/editor/examples/tweet/tweet-view.tsx b/react-tweet/src/components/editor/examples/tweet/tweet-view.tsx deleted file mode 100644 index 78d1313ac8..0000000000 --- a/react-tweet/src/components/editor/examples/tweet/tweet-view.tsx +++ /dev/null @@ -1,27 +0,0 @@ -'use client' - -import type { ReactNodeViewProps } from 'prosekit/react' -import { Tweet } from 'react-tweet' - -export function TweetView({ node }: ReactNodeViewProps) { - const tweetId = node.attrs.tweetId as string - return ( -
-
- - Rendered in React using library{' '} - - - react-tweet - - - -
- -
- ) -} diff --git a/react-tweet/src/components/editor/sample/sample-doc-tweet.ts b/react-tweet/src/components/editor/sample/sample-doc-tweet.ts deleted file mode 100644 index f0c0e6ca60..0000000000 --- a/react-tweet/src/components/editor/sample/sample-doc-tweet.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Render a tweet in your document', - }, - ], - }, - { - type: 'tweet', - attrs: { - tweetId: '20', - }, - }, - ], -} diff --git a/react-tweet/src/main.tsx b/react-tweet/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-tweet/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-tweet/tsconfig.app.json b/react-tweet/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-tweet/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-tweet/tsconfig.json b/react-tweet/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-tweet/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-tweet/tsconfig.node.json b/react-tweet/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-tweet/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-tweet/vite.config.ts b/react-tweet/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-tweet/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-typography/.gitignore b/react-typography/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-typography/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-typography/README.md b/react-typography/README.md deleted file mode 100644 index f57c81da83..0000000000 --- a/react-typography/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-typography - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-typography) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-typography) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-typography react-typography -cd react-typography -npm install -npm run dev -``` diff --git a/react-typography/index.html b/react-typography/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-typography/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-typography/package.json b/react-typography/package.json deleted file mode 100644 index 5e39739255..0000000000 --- a/react-typography/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-react-typography", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-typography/src/App.tsx b/react-typography/src/App.tsx deleted file mode 100644 index e1a59aa483..0000000000 --- a/react-typography/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/typography' - -export default function App() { - return -} diff --git a/react-typography/src/app.css b/react-typography/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-typography/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-typography/src/components/editor/examples/typography/editor.tsx b/react-typography/src/components/editor/examples/typography/editor.tsx deleted file mode 100644 index 94f229b751..0000000000 --- a/react-typography/src/components/editor/examples/typography/editor.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-typography' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/react-typography/src/components/editor/examples/typography/extension.ts b/react-typography/src/components/editor/examples/typography/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/react-typography/src/components/editor/examples/typography/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-typography/src/components/editor/examples/typography/index.ts b/react-typography/src/components/editor/examples/typography/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-typography/src/components/editor/examples/typography/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-typography/src/components/editor/sample/katex.ts b/react-typography/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/react-typography/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/react-typography/src/components/editor/sample/sample-doc-typography.ts b/react-typography/src/components/editor/sample/sample-doc-typography.ts deleted file mode 100644 index db18b8155c..0000000000 --- a/react-typography/src/components/editor/sample/sample-doc-typography.ts +++ /dev/null @@ -1,693 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'ProseKit Typography', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This example shows the typography styles provided by ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'prosekit/basic/typography.css', - }, - { - type: 'text', - text: '.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Inline marks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Text can be formatted in different ways: ', - }, - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'bold text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'italic text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'underlined text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'strikethrough text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'inline code', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://example.com', - target: null, - rel: null, - }, - }, - ], - text: 'links', - }, - { - type: 'text', - text: ',', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'and hard breaks (Shift+Enter).', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Headings', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Heading 1', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Heading 2', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Heading 3', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 4, - }, - content: [ - { - type: 'text', - text: 'Heading 4', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 5, - }, - content: [ - { - type: 'text', - text: 'Heading 5', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 6, - }, - content: [ - { - type: 'text', - text: 'Heading 6', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Lists', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here are different types of lists:', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 1', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 2', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item A', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item B', - }, - ], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'First ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Second ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: true, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Completed task', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Pending task', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Blockquotes', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: '', - }, - content: [ - { - type: 'text', - text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Horizontal Rule', - }, - ], - }, - { - type: 'horizontalRule', - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blurred/640x360/42', - }, - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Tables', - }, - ], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 1', - }, - ], - }, - ], - }, - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 3', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 4', - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Math', - }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Inline math like Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text.' }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Block-level equations are displayed on their own line:', - }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - ], -} diff --git a/react-typography/src/components/editor/ui/block-handle/block-handle.tsx b/react-typography/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 3cc6028d5c..0000000000 --- a/react-typography/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,33 +0,0 @@ -'use client' - -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/react/block-handle' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props) { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/react-typography/src/components/editor/ui/block-handle/index.ts b/react-typography/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/react-typography/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/react-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/react-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx deleted file mode 100644 index 87c1746622..0000000000 --- a/react-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx +++ /dev/null @@ -1,7 +0,0 @@ -'use client' - -import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator' - -export default function DropIndicator() { - return -} diff --git a/react-typography/src/components/editor/ui/drop-indicator/index.ts b/react-typography/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index f8fb7139c4..0000000000 --- a/react-typography/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator' diff --git a/react-typography/src/main.tsx b/react-typography/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-typography/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-typography/tsconfig.app.json b/react-typography/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-typography/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-typography/tsconfig.json b/react-typography/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-typography/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-typography/tsconfig.node.json b/react-typography/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-typography/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-typography/vite.config.ts b/react-typography/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-typography/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-underline/.gitignore b/react-underline/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-underline/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-underline/README.md b/react-underline/README.md deleted file mode 100644 index 2686efd803..0000000000 --- a/react-underline/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-underline - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-underline) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-underline) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-underline react-underline -cd react-underline -npm install -npm run dev -``` diff --git a/react-underline/index.html b/react-underline/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-underline/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-underline/package.json b/react-underline/package.json deleted file mode 100644 index f090213bf3..0000000000 --- a/react-underline/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-underline", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-underline/src/App.tsx b/react-underline/src/App.tsx deleted file mode 100644 index 6a03ee7870..0000000000 --- a/react-underline/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/underline' - -export default function App() { - return -} diff --git a/react-underline/src/app.css b/react-underline/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-underline/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-underline/src/components/editor/examples/underline/editor.tsx b/react-underline/src/components/editor/examples/underline/editor.tsx deleted file mode 100644 index a53df8f9d7..0000000000 --- a/react-underline/src/components/editor/examples/underline/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-underline' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension, defaultContent }) - }, [defaultContent]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-underline/src/components/editor/examples/underline/extension.ts b/react-underline/src/components/editor/examples/underline/extension.ts deleted file mode 100644 index 16a9b58284..0000000000 --- a/react-underline/src/components/editor/examples/underline/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineUnderline(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-underline/src/components/editor/examples/underline/index.ts b/react-underline/src/components/editor/examples/underline/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-underline/src/components/editor/examples/underline/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-underline/src/components/editor/sample/sample-doc-underline.ts b/react-underline/src/components/editor/sample/sample-doc-underline.ts deleted file mode 100644 index 6af561064b..0000000000 --- a/react-underline/src/components/editor/sample/sample-doc-underline.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'This is underline', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/react-underline/src/components/editor/ui/button/button.tsx b/react-underline/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-underline/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-underline/src/components/editor/ui/button/index.ts b/react-underline/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-underline/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-underline/src/components/editor/ui/image-upload-popover/index.ts b/react-underline/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-underline/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-underline/src/components/editor/ui/toolbar/index.ts b/react-underline/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-underline/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-underline/src/components/editor/ui/toolbar/toolbar.tsx b/react-underline/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-underline/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-underline/src/main.tsx b/react-underline/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-underline/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-underline/tsconfig.app.json b/react-underline/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-underline/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-underline/tsconfig.json b/react-underline/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-underline/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-underline/tsconfig.node.json b/react-underline/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-underline/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-underline/vite.config.ts b/react-underline/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-underline/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-unmount/.gitignore b/react-unmount/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-unmount/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-unmount/README.md b/react-unmount/README.md deleted file mode 100644 index bc8713cc6a..0000000000 --- a/react-unmount/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-unmount - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-unmount) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-unmount) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-unmount react-unmount -cd react-unmount -npm install -npm run dev -``` diff --git a/react-unmount/index.html b/react-unmount/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-unmount/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-unmount/package.json b/react-unmount/package.json deleted file mode 100644 index e728681abe..0000000000 --- a/react-unmount/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-unmount", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-unmount/src/App.tsx b/react-unmount/src/App.tsx deleted file mode 100644 index da35bea56f..0000000000 --- a/react-unmount/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/unmount' - -export default function App() { - return -} diff --git a/react-unmount/src/app.css b/react-unmount/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-unmount/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-unmount/src/components/editor/examples/unmount/editor-component.tsx b/react-unmount/src/components/editor/examples/unmount/editor-component.tsx deleted file mode 100644 index dac49ebeaa..0000000000 --- a/react-unmount/src/components/editor/examples/unmount/editor-component.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { InlineMenu } from '../../ui/inline-menu' - -import ExtensionComponent from './extension-component' - -export default function EditorComponent(props: { placeholder: string }) { - const editor = useMemo(() => { - return createEditor({ extension: defineBasicExtension() }) - }, []) - - return ( - -
-
-
- -
-
- -
- ) -} diff --git a/react-unmount/src/components/editor/examples/unmount/editor.tsx b/react-unmount/src/components/editor/examples/unmount/editor.tsx deleted file mode 100644 index c970e2961c..0000000000 --- a/react-unmount/src/components/editor/examples/unmount/editor.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { useCallback, useRef, useState } from 'react' - -import EditorComponent from './editor-component' - -function EditorGroup() { - const nextKeyRef = useRef(1) - const [editorKeys, setEditorKeys] = useState([]) - - const addEditor = useCallback(() => { - const key = nextKeyRef.current - nextKeyRef.current += 1 - setEditorKeys((keys) => [...keys, key]) - }, []) - - const removeEditor = useCallback((key: number) => { - setEditorKeys((keys) => keys.filter((k) => k !== key)) - }, []) - - return ( -
-
- - {editorKeys.map((key) => ( - - ))} -
- {editorKeys.map((key) => ( -
- -
- ))} -
- ) -} - -export default EditorGroup diff --git a/react-unmount/src/components/editor/examples/unmount/extension-component.tsx b/react-unmount/src/components/editor/examples/unmount/extension-component.tsx deleted file mode 100644 index 54dcf9e0b0..0000000000 --- a/react-unmount/src/components/editor/examples/unmount/extension-component.tsx +++ /dev/null @@ -1,16 +0,0 @@ -'use client' - -import { definePlaceholder } from 'prosekit/extensions/placeholder' -import { useExtension } from 'prosekit/react' -import { useMemo } from 'react' - -export default function ExtensionComponent(props: { placeholder: string }) { - const extension = useMemo( - () => definePlaceholder({ placeholder: props.placeholder }), - [props.placeholder], - ) - - useExtension(extension) - - return null -} diff --git a/react-unmount/src/components/editor/examples/unmount/index.ts b/react-unmount/src/components/editor/examples/unmount/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-unmount/src/components/editor/examples/unmount/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-unmount/src/components/editor/ui/button/button.tsx b/react-unmount/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-unmount/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-unmount/src/components/editor/ui/button/index.ts b/react-unmount/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-unmount/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-unmount/src/components/editor/ui/inline-menu/index.ts b/react-unmount/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/react-unmount/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/react-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index af1b2bb2b7..0000000000 --- a/react-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,221 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/react' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/react/inline-popover' -import { useState } from 'react' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu() { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = useState(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor.commands.addLink({ href }) - } else { - editor.commands.removeLink() - } - - setLinkMenuOpen(false) - editor.focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.link && items.link.canExec && ( - - )} - - - - - {items.link && ( - setLinkMenuOpen(event.detail)} - > - - - {linkMenuOpen && ( -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- )} - {items.link.isActive && ( - - )} -
-
-
- )} - - ) -} diff --git a/react-unmount/src/main.tsx b/react-unmount/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-unmount/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-unmount/tsconfig.app.json b/react-unmount/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-unmount/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-unmount/tsconfig.json b/react-unmount/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-unmount/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-unmount/tsconfig.node.json b/react-unmount/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-unmount/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-unmount/vite.config.ts b/react-unmount/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-unmount/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-user-menu-dynamic/.gitignore b/react-user-menu-dynamic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-user-menu-dynamic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-user-menu-dynamic/README.md b/react-user-menu-dynamic/README.md deleted file mode 100644 index a37811c5c5..0000000000 --- a/react-user-menu-dynamic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-user-menu-dynamic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-user-menu-dynamic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-user-menu-dynamic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-user-menu-dynamic react-user-menu-dynamic -cd react-user-menu-dynamic -npm install -npm run dev -``` diff --git a/react-user-menu-dynamic/index.html b/react-user-menu-dynamic/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-user-menu-dynamic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-user-menu-dynamic/package.json b/react-user-menu-dynamic/package.json deleted file mode 100644 index 45287eed9d..0000000000 --- a/react-user-menu-dynamic/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-user-menu-dynamic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-user-menu-dynamic/src/App.tsx b/react-user-menu-dynamic/src/App.tsx deleted file mode 100644 index e3ec0e7b10..0000000000 --- a/react-user-menu-dynamic/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/user-menu-dynamic' - -export default function App() { - return -} diff --git a/react-user-menu-dynamic/src/app.css b/react-user-menu-dynamic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-user-menu-dynamic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx deleted file mode 100644 index 966c2b115e..0000000000 --- a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx +++ /dev/null @@ -1,32 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { defineExtension } from './extension' -import UserMenuDynamic from './user-menu-dynamic' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts deleted file mode 100644 index ff2c40b104..0000000000 --- a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts deleted file mode 100644 index 0d2151d2b0..0000000000 --- a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { useEffect, useState } from 'react' - -import type { User } from '../../sample/sample-query-users' -import { queryUsers } from '../../sample/sample-query-users' - -/** - * Simulate a user searching with some delay. - */ -export function useUserQuery(query: string, enabled: boolean) { - const [users, setUsers] = useState([]) - const [loading, setLoading] = useState(true) - - if (!enabled && users.length > 0) { - setUsers([]) - } - - useEffect(() => { - if (!enabled) { - return - } - - let cancelled = false - - void (async () => { - setLoading(true) - const filteredUsers = await queryUsers(query) - if (cancelled) { - return - } - setUsers(filteredUsers) - setLoading(false) - })() - - return () => { - cancelled = true - } - }, [enabled, query]) - - return { loading, users } -} diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx deleted file mode 100644 index 2e873dca40..0000000000 --- a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client' - -import { useState } from 'react' - -import { UserMenu } from '../../ui/user-menu' - -import { useUserQuery } from './use-user-query' - -export default function UserMenuDynamic() { - const [query, setQuery] = useState('') - const [open, setOpen] = useState(false) - - const { loading, users } = useUserQuery(query, open) - - return ( - - ) -} diff --git a/react-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/react-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts deleted file mode 100644 index ab78fd5525..0000000000 --- a/react-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { users } from './sample-user-data' - -export interface User { - id: number - name: string -} - -const connectHandlers: VoidFunction[] = [] -let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' - -/** - * A utility function to simulate different network states. Useful for testing. - * - * @internal - */ -export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { - networkStatus = status - if (status !== 'offline') { - connectHandlers.forEach((handler) => handler()) - connectHandlers.length = 0 - } -} - -/** - * Simulate a user searching with some delay. - */ -export async function queryUsers(query: string): Promise { - if (networkStatus === 'offline') { - await new Promise((resolve) => connectHandlers.push(resolve)) - } - if (networkStatus === 'slow') { - await new Promise((resolve) => setTimeout(resolve, 300)) - } - - const normalizedQuery = query.toLowerCase().trim() - const filteredUsers = users - .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) - .slice(0, 10) - return filteredUsers -} diff --git a/react-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/react-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/react-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/react-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/react-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/react-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/react-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx b/react-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 46555f6382..0000000000 --- a/react-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,64 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/react' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}) { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - {props.users.map((user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - ))} -
-
-
-
- ) -} diff --git a/react-user-menu-dynamic/src/main.tsx b/react-user-menu-dynamic/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-user-menu-dynamic/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-user-menu-dynamic/tsconfig.app.json b/react-user-menu-dynamic/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-user-menu-dynamic/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-user-menu-dynamic/tsconfig.json b/react-user-menu-dynamic/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-user-menu-dynamic/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-user-menu-dynamic/tsconfig.node.json b/react-user-menu-dynamic/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-user-menu-dynamic/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-user-menu-dynamic/vite.config.ts b/react-user-menu-dynamic/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-user-menu-dynamic/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-user-menu/.gitignore b/react-user-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-user-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-user-menu/README.md b/react-user-menu/README.md deleted file mode 100644 index 5fce6fb80e..0000000000 --- a/react-user-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-user-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-user-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-user-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-user-menu react-user-menu -cd react-user-menu -npm install -npm run dev -``` diff --git a/react-user-menu/index.html b/react-user-menu/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-user-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-user-menu/package.json b/react-user-menu/package.json deleted file mode 100644 index 879a70750e..0000000000 --- a/react-user-menu/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-user-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-user-menu/src/App.tsx b/react-user-menu/src/App.tsx deleted file mode 100644 index 92fca03d42..0000000000 --- a/react-user-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/user-menu' - -export default function App() { - return -} diff --git a/react-user-menu/src/app.css b/react-user-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-user-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-user-menu/src/components/editor/examples/user-menu/editor.tsx b/react-user-menu/src/components/editor/examples/user-menu/editor.tsx deleted file mode 100644 index c0c8c65162..0000000000 --- a/react-user-menu/src/components/editor/examples/user-menu/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { tags } from '../../sample/sample-tag-data' -import { users } from '../../sample/sample-user-data' -import { TagMenu } from '../../ui/tag-menu' -import { UserMenu } from '../../ui/user-menu' - -import { defineExtension } from './extension' - -export default function Editor() { - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ extension }) - }, []) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/react-user-menu/src/components/editor/examples/user-menu/extension.ts b/react-user-menu/src/components/editor/examples/user-menu/extension.ts deleted file mode 100644 index 56a97a4779..0000000000 --- a/react-user-menu/src/components/editor/examples/user-menu/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone or # to tag something...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/react-user-menu/src/components/editor/examples/user-menu/index.ts b/react-user-menu/src/components/editor/examples/user-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-user-menu/src/components/editor/examples/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-user-menu/src/components/editor/sample/sample-tag-data.ts b/react-user-menu/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/react-user-menu/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/react-user-menu/src/components/editor/sample/sample-user-data.ts b/react-user-menu/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/react-user-menu/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/react-user-menu/src/components/editor/ui/tag-menu/index.ts b/react-user-menu/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index d344b33a70..0000000000 --- a/react-user-menu/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu' diff --git a/react-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx b/react-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx deleted file mode 100644 index 711486fcf7..0000000000 --- a/react-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx +++ /dev/null @@ -1,54 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/react' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -const regex = /#[\da-z]*$/i - -export default function TagMenu(props: { - tags: { id: number; label: string }[] -}) { - const editor = useEditor>() - - const handleTagInsert = (id: number, label: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '#' + label, - kind: 'tag', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - - - -
- - No results - - - {props.tags.map((tag) => ( - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - ))} -
-
-
-
- ) -} diff --git a/react-user-menu/src/components/editor/ui/user-menu/index.ts b/react-user-menu/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/react-user-menu/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/react-user-menu/src/components/editor/ui/user-menu/user-menu.tsx b/react-user-menu/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 46555f6382..0000000000 --- a/react-user-menu/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,64 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/react' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/react/autocomplete' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}) { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor.commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor.commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - {props.users.map((user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - ))} -
-
-
-
- ) -} diff --git a/react-user-menu/src/main.tsx b/react-user-menu/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-user-menu/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-user-menu/tsconfig.app.json b/react-user-menu/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-user-menu/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-user-menu/tsconfig.json b/react-user-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-user-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-user-menu/tsconfig.node.json b/react-user-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-user-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-user-menu/vite.config.ts b/react-user-menu/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-user-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-word-counter/.gitignore b/react-word-counter/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-word-counter/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-word-counter/README.md b/react-word-counter/README.md deleted file mode 100644 index 9b868dc92e..0000000000 --- a/react-word-counter/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-word-counter - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-word-counter) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-word-counter) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-word-counter react-word-counter -cd react-word-counter -npm install -npm run dev -``` diff --git a/react-word-counter/index.html b/react-word-counter/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-word-counter/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-word-counter/package.json b/react-word-counter/package.json deleted file mode 100644 index 19f0b053ad..0000000000 --- a/react-word-counter/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-word-counter", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-word-counter/src/App.tsx b/react-word-counter/src/App.tsx deleted file mode 100644 index 9da98dddb5..0000000000 --- a/react-word-counter/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/word-counter' - -export default function App() { - return -} diff --git a/react-word-counter/src/app.css b/react-word-counter/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-word-counter/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-word-counter/src/components/editor/examples/word-counter/editor.tsx b/react-word-counter/src/components/editor/examples/word-counter/editor.tsx deleted file mode 100644 index 3928af8804..0000000000 --- a/react-word-counter/src/components/editor/examples/word-counter/editor.tsx +++ /dev/null @@ -1,42 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' - -import { sampleContent } from '../../sample/sample-doc-word-counter' -import { WordCounter } from '../../ui/word-counter' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps) { - const defaultContent = props.initialContent ?? sampleContent - const editor = useMemo(() => { - const extension = defineExtension() - return createEditor({ - extension, - defaultContent, - }) - }, [defaultContent]) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/react-word-counter/src/components/editor/examples/word-counter/extension.ts b/react-word-counter/src/components/editor/examples/word-counter/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/react-word-counter/src/components/editor/examples/word-counter/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/react-word-counter/src/components/editor/examples/word-counter/index.ts b/react-word-counter/src/components/editor/examples/word-counter/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-word-counter/src/components/editor/examples/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/react-word-counter/src/components/editor/sample/sample-doc-word-counter.ts deleted file mode 100644 index 0b5d435038..0000000000 --- a/react-word-counter/src/components/editor/sample/sample-doc-word-counter.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Start typing and observe the word count update below.', - }, - ], - }, - ], -} diff --git a/react-word-counter/src/components/editor/ui/word-counter/index.ts b/react-word-counter/src/components/editor/ui/word-counter/index.ts deleted file mode 100644 index 929ee3e41a..0000000000 --- a/react-word-counter/src/components/editor/ui/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as WordCounter } from './word-counter' diff --git a/react-word-counter/src/components/editor/ui/word-counter/word-counter.tsx b/react-word-counter/src/components/editor/ui/word-counter/word-counter.tsx deleted file mode 100644 index 24407adc3b..0000000000 --- a/react-word-counter/src/components/editor/ui/word-counter/word-counter.tsx +++ /dev/null @@ -1,24 +0,0 @@ -'use client' - -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/react' - -function getWordCount(editor: Editor) { - const doc = editor.state.doc - const words = doc ? doc.textBetween(0, doc.content.size, ' ') : '' - const wordCount = words.split(/\s+/).filter((s) => s).length - const characterCount = doc ? doc.textContent.length : 0 - return { wordCount, characterCount } -} - -export default function WordCounter() { - const { wordCount, characterCount } = useEditorDerivedValue(getWordCount) - - return ( -
- Word Count: {wordCount} -
- Character Count: {characterCount} -
- ) -} diff --git a/react-word-counter/src/main.tsx b/react-word-counter/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-word-counter/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-word-counter/tsconfig.app.json b/react-word-counter/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-word-counter/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-word-counter/tsconfig.json b/react-word-counter/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-word-counter/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-word-counter/tsconfig.node.json b/react-word-counter/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-word-counter/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-word-counter/vite.config.ts b/react-word-counter/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-word-counter/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/react-yjs/.gitignore b/react-yjs/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/react-yjs/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/react-yjs/README.md b/react-yjs/README.md deleted file mode 100644 index d9790248f2..0000000000 --- a/react-yjs/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# react-yjs - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-yjs) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-yjs) - -Run the example locally with: - -```bash -npx degit prosekit/examples/react-yjs react-yjs -cd react-yjs -npm install -npm run dev -``` diff --git a/react-yjs/index.html b/react-yjs/index.html deleted file mode 100644 index a5a78f3bf8..0000000000 --- a/react-yjs/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + React - - -
- - - diff --git a/react-yjs/package.json b/react-yjs/package.json deleted file mode 100644 index ac131cb335..0000000000 --- a/react-yjs/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "example-react-yjs", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "react": "^19.2.6", - "react-dom": "^19.2.6", - "y-prosemirror": "^1.3.7", - "y-protocols": "^1.0.7", - "y-websocket": "^3.0.0", - "yjs": "^13.6.30" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@types/react": "^19.2.14", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^6.0.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/react-yjs/src/App.tsx b/react-yjs/src/App.tsx deleted file mode 100644 index 8641aefe47..0000000000 --- a/react-yjs/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/yjs' - -export default function App() { - return -} diff --git a/react-yjs/src/app.css b/react-yjs/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/react-yjs/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/react-yjs/src/components/editor/examples/yjs/editor-component.tsx b/react-yjs/src/components/editor/examples/yjs/editor-component.tsx deleted file mode 100644 index c35b61ad0a..0000000000 --- a/react-yjs/src/components/editor/examples/yjs/editor-component.tsx +++ /dev/null @@ -1,43 +0,0 @@ -'use client' - -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/yjs/style.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/react' -import { useMemo } from 'react' -import { WebsocketProvider } from 'y-websocket' -import * as Y from 'yjs' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function EditorComponent(props: { room?: string }) { - const editor = useMemo(() => { - const doc = new Y.Doc() - const provider = new WebsocketProvider( - 'wss://demos.yjs.dev/ws', - `github.com/prosekit/room_${props.room}`, - doc, - ) - - const extension = defineExtension(doc, provider.awareness) - return createEditor({ extension }) - }, [props.room]) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/react-yjs/src/components/editor/examples/yjs/editor.tsx b/react-yjs/src/components/editor/examples/yjs/editor.tsx deleted file mode 100644 index a7c8a5d94b..0000000000 --- a/react-yjs/src/components/editor/examples/yjs/editor.tsx +++ /dev/null @@ -1,18 +0,0 @@ -'use client' - -import { useState } from 'react' - -import EditorComponent from './editor-component' - -export default function Page() { - const [room] = useState(() => { - return Math.random().toString(36).substring(2, 15) - }) - - return ( -
- - -
- ) -} diff --git a/react-yjs/src/components/editor/examples/yjs/extension.ts b/react-yjs/src/components/editor/examples/yjs/extension.ts deleted file mode 100644 index f1a581932b..0000000000 --- a/react-yjs/src/components/editor/examples/yjs/extension.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' -import { defineYjs } from 'prosekit/extensions/yjs' -import type { Awareness } from 'prosekit/extensions/yjs' -import type * as Y from 'yjs' - -export function defineExtension(doc: Y.Doc, awareness: Awareness) { - return union([ - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineYjs({ doc, awareness }), - ]) -} - -export type EditorExtension = ReturnType diff --git a/react-yjs/src/components/editor/examples/yjs/index.ts b/react-yjs/src/components/editor/examples/yjs/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/react-yjs/src/components/editor/examples/yjs/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/react-yjs/src/components/editor/ui/button/button.tsx b/react-yjs/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a9d125a429..0000000000 --- a/react-yjs/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client' - -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/react/tooltip' -import type { MouseEventHandler, ReactNode } from 'react' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: MouseEventHandler - tooltip?: string - children: ReactNode -}) { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/react-yjs/src/components/editor/ui/button/index.ts b/react-yjs/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/react-yjs/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/react-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index 808361b6ad..0000000000 --- a/react-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,145 +0,0 @@ -'use client' - -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/react' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/react/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { useId, useState, type ReactNode } from 'react' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: ReactNode -}) { - const [open, setOpen] = useState(false) - const [url, setUrl] = useState('') - const [file, setFile] = useState(null) - const ariaId = useId() - - const editor = useEditor() - - const handleFileChange: React.ChangeEventHandler = ( - event, - ) => { - const file = event.target.files?.[0] - - if (file) { - setFile(file) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange: React.ChangeEventHandler = ( - event, - ) => { - const url = event.target.value - - if (url) { - setUrl(url) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url) { - editor.commands.insertImage({ src: url }) - } else if (file) { - editor.commands.uploadImage({ file, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - {file ? null : ( - <> - - - - )} - - {url ? null : ( - <> - - - - )} - - {url ? ( - - ) : null} - - {file ? ( - - ) : null} - - - - ) -} diff --git a/react-yjs/src/components/editor/ui/image-upload-popover/index.ts b/react-yjs/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/react-yjs/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-yjs/src/components/editor/ui/toolbar/index.ts b/react-yjs/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/react-yjs/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/react-yjs/src/components/editor/ui/toolbar/toolbar.tsx b/react-yjs/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ce61a2d041..0000000000 --- a/react-yjs/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,365 +0,0 @@ -'use client' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/react' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { uploader?: Uploader }) { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- {items.undo && ( - - )} - {items.redo && ( - - )} - - {items.bold && ( - - )} - {items.italic && ( - - )} - {items.underline && ( - - )} - {items.strike && ( - - )} - {items.code && ( - - )} - {items.codeBlock && ( - - )} - {items.heading1 && ( - - )} - {items.heading2 && ( - - )} - {items.heading3 && ( - - )} - {items.horizontalRule && ( - - )} - {items.blockquote && ( - - )} - {items.bulletList && ( - - )} - {items.orderedList && ( - - )} - {items.taskList && ( - - )} - {items.toggleList && ( - - )} - {items.indentList && ( - - )} - {items.dedentList && ( - - )} - {props.uploader && items.insertImage && ( - -
- - )} -
- ) -} diff --git a/react-yjs/src/main.tsx b/react-yjs/src/main.tsx deleted file mode 100644 index 87de8eb52b..0000000000 --- a/react-yjs/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import './app.css' -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - , -) diff --git a/react-yjs/tsconfig.app.json b/react-yjs/tsconfig.app.json deleted file mode 100644 index a9b5a59ca6..0000000000 --- a/react-yjs/tsconfig.app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "react-jsx", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/react-yjs/tsconfig.json b/react-yjs/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/react-yjs/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/react-yjs/tsconfig.node.json b/react-yjs/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/react-yjs/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/react-yjs/vite.config.ts b/react-yjs/vite.config.ts deleted file mode 100644 index c90997597d..0000000000 --- a/react-yjs/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react(), tailwindcss()], -}) diff --git a/solid-block-handle/.gitignore b/solid-block-handle/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-block-handle/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-block-handle/README.md b/solid-block-handle/README.md deleted file mode 100644 index 83b6bbf0f8..0000000000 --- a/solid-block-handle/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-block-handle - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-block-handle) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-block-handle) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-block-handle solid-block-handle -cd solid-block-handle -npm install -npm run dev -``` diff --git a/solid-block-handle/index.html b/solid-block-handle/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-block-handle/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-block-handle/package.json b/solid-block-handle/package.json deleted file mode 100644 index 4c14b94cb2..0000000000 --- a/solid-block-handle/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-block-handle", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-block-handle/src/App.tsx b/solid-block-handle/src/App.tsx deleted file mode 100644 index 2cb5b6bb8d..0000000000 --- a/solid-block-handle/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/block-handle' - -export default function App() { - return -} diff --git a/solid-block-handle/src/app.css b/solid-block-handle/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-block-handle/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-block-handle/src/components/editor/examples/block-handle/editor.tsx b/solid-block-handle/src/components/editor/examples/block-handle/editor.tsx deleted file mode 100644 index f98ab63fdc..0000000000 --- a/solid-block-handle/src/components/editor/examples/block-handle/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-block-handle' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const extension = defineExtension() - const defaultContent = props.initialContent ?? sampleContent - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/solid-block-handle/src/components/editor/examples/block-handle/extension.ts b/solid-block-handle/src/components/editor/examples/block-handle/extension.ts deleted file mode 100644 index b5686b8c04..0000000000 --- a/solid-block-handle/src/components/editor/examples/block-handle/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union(defineBasicExtension(), defineCodeBlockView()) -} - -export type EditorExtension = ReturnType diff --git a/solid-block-handle/src/components/editor/examples/block-handle/index.ts b/solid-block-handle/src/components/editor/examples/block-handle/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-block-handle/src/components/editor/examples/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/solid-block-handle/src/components/editor/sample/sample-doc-block-handle.ts deleted file mode 100644 index 3c6ccdc203..0000000000 --- a/solid-block-handle/src/components/editor/sample/sample-doc-block-handle.ts +++ /dev/null @@ -1,323 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Drag and Drop Demo', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Getting Started', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This paragraph can be moved above or below other blocks.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Different Block Types', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'You can drag paragraphs, headings, lists, code blocks, and more.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Lists Work Too', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This entire list can be dragged', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Individual list items stay together', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try moving this list around', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Ordered lists also support dragging', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The numbering updates automatically', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag this list to see it in action', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Even code blocks can be moved:', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: 'javascript', - }, - content: [ - { - type: 'text', - text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Nested Content', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This blockquote can be moved as a single unit.', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested blockquotes move together with their parent.', - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Try It Yourself', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Practice by moving this paragraph to the top of the document.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Or drag this one to between the headings above.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The drag handles make it easy to reorganize your content exactly how you want it.', - }, - ], - }, - ], -} diff --git a/solid-block-handle/src/components/editor/ui/block-handle/block-handle.tsx b/solid-block-handle/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 95e1693ef6..0000000000 --- a/solid-block-handle/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/solid/block-handle' -import type { JSX } from 'solid-js' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props): JSX.Element { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/solid-block-handle/src/components/editor/ui/block-handle/index.ts b/solid-block-handle/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/solid-block-handle/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/solid-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx b/solid-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index 2d67b563f7..0000000000 --- a/solid-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { SolidNodeViewProps } from 'prosekit/solid' -import { For, type JSX } from 'solid-js' - -export default function CodeBlockView(props: SolidNodeViewProps): JSX.Element { - const attrs = () => props.node.attrs as CodeBlockAttrs - const language = () => attrs().language - - const setLanguage = (lang: string) => { - const newAttrs: CodeBlockAttrs = { language: lang } - props.setAttrs(newAttrs) - } - - return ( - <> - -

-    
-  )
-}
diff --git a/solid-block-handle/src/components/editor/ui/code-block-view/index.ts b/solid-block-handle/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index 50bbbea7df..0000000000
--- a/solid-block-handle/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSolidNodeView,
-  type SolidNodeViewComponent,
-} from 'prosekit/solid'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineSolidNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies SolidNodeViewComponent,
-  })
-}
diff --git a/solid-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/solid-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
deleted file mode 100644
index c5a24c7faa..0000000000
--- a/solid-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import { DropIndicator as BaseDropIndicator } from 'prosekit/solid/drop-indicator'
-import type { JSX } from 'solid-js'
-
-export default function DropIndicator(): JSX.Element {
-  return 
-}
diff --git a/solid-block-handle/src/components/editor/ui/drop-indicator/index.ts b/solid-block-handle/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index f8fb7139c4..0000000000
--- a/solid-block-handle/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator'
diff --git a/solid-block-handle/src/index.tsx b/solid-block-handle/src/index.tsx
deleted file mode 100644
index 92b7740757..0000000000
--- a/solid-block-handle/src/index.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-/* @refresh reload */
-import './app.css'
-import { render } from 'solid-js/web'
-import App from './App'
-
-const root = document.getElementById('root')
-
-render(() => , root!)
diff --git a/solid-block-handle/tsconfig.app.json b/solid-block-handle/tsconfig.app.json
deleted file mode 100644
index c0b480e758..0000000000
--- a/solid-block-handle/tsconfig.app.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
-    "target": "ES2022",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "lib": ["ES2022", "DOM", "DOM.Iterable"],
-    "types": ["vite/client"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-    "jsx": "preserve",
-    "jsxImportSource": "solid-js",
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["src"]
-}
diff --git a/solid-block-handle/tsconfig.json b/solid-block-handle/tsconfig.json
deleted file mode 100644
index 1ffef600d9..0000000000
--- a/solid-block-handle/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "files": [],
-  "references": [
-    { "path": "./tsconfig.app.json" },
-    { "path": "./tsconfig.node.json" }
-  ]
-}
diff --git a/solid-block-handle/tsconfig.node.json b/solid-block-handle/tsconfig.node.json
deleted file mode 100644
index 8a67f62f4c..0000000000
--- a/solid-block-handle/tsconfig.node.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
-    "target": "ES2023",
-    "lib": ["ES2023"],
-    "module": "ESNext",
-    "types": ["node"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/solid-block-handle/vite.config.ts b/solid-block-handle/vite.config.ts
deleted file mode 100644
index 9cb3cb51fd..0000000000
--- a/solid-block-handle/vite.config.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { defineConfig } from 'vite'
-import solid from 'vite-plugin-solid'
-import tailwindcss from '@tailwindcss/vite'
-
-export default defineConfig({
-  plugins: [solid(), tailwindcss()],
-})
diff --git a/solid-blockquote/.gitignore b/solid-blockquote/.gitignore
deleted file mode 100644
index 5d6225c6df..0000000000
--- a/solid-blockquote/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-dist
-.next
-.svelte-kit
diff --git a/solid-blockquote/README.md b/solid-blockquote/README.md
deleted file mode 100644
index fcb3d7f858..0000000000
--- a/solid-blockquote/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# solid-blockquote
-
-A [ProseKit](https://prosekit.dev) example.
-
-[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-blockquote)
-[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-blockquote)
-
-Run the example locally with:
-
-```bash
-npx degit prosekit/examples/solid-blockquote solid-blockquote
-cd solid-blockquote
-npm install
-npm run dev
-```
diff --git a/solid-blockquote/index.html b/solid-blockquote/index.html
deleted file mode 100644
index 375ea8dbc4..0000000000
--- a/solid-blockquote/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-  
-    
-    
-    ProseKit + Solid
-  
-  
-    
- - - diff --git a/solid-blockquote/package.json b/solid-blockquote/package.json deleted file mode 100644 index 6018436295..0000000000 --- a/solid-blockquote/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-blockquote", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-blockquote/src/App.tsx b/solid-blockquote/src/App.tsx deleted file mode 100644 index 3327cfcf2d..0000000000 --- a/solid-blockquote/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/blockquote' - -export default function App() { - return -} diff --git a/solid-blockquote/src/app.css b/solid-blockquote/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-blockquote/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-blockquote/src/components/editor/examples/blockquote/editor.tsx b/solid-blockquote/src/components/editor/examples/blockquote/editor.tsx deleted file mode 100644 index 05c47ad54e..0000000000 --- a/solid-blockquote/src/components/editor/examples/blockquote/editor.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-blockquote/src/components/editor/examples/blockquote/extension.ts b/solid-blockquote/src/components/editor/examples/blockquote/extension.ts deleted file mode 100644 index 5292b59e35..0000000000 --- a/solid-blockquote/src/components/editor/examples/blockquote/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBlockquote(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-blockquote/src/components/editor/examples/blockquote/index.ts b/solid-blockquote/src/components/editor/examples/blockquote/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-blockquote/src/components/editor/examples/blockquote/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-blockquote/src/components/editor/ui/button/button.tsx b/solid-blockquote/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-blockquote/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-blockquote/src/components/editor/ui/button/index.ts b/solid-blockquote/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-blockquote/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/solid-blockquote/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-blockquote/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-blockquote/src/components/editor/ui/toolbar/index.ts b/solid-blockquote/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-blockquote/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-blockquote/src/components/editor/ui/toolbar/toolbar.tsx b/solid-blockquote/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-blockquote/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-blockquote/src/index.tsx b/solid-blockquote/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-blockquote/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-blockquote/tsconfig.app.json b/solid-blockquote/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-blockquote/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-blockquote/tsconfig.json b/solid-blockquote/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-blockquote/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-blockquote/tsconfig.node.json b/solid-blockquote/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-blockquote/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-blockquote/vite.config.ts b/solid-blockquote/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-blockquote/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-bold/.gitignore b/solid-bold/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-bold/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-bold/README.md b/solid-bold/README.md deleted file mode 100644 index b089887930..0000000000 --- a/solid-bold/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-bold - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-bold) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-bold) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-bold solid-bold -cd solid-bold -npm install -npm run dev -``` diff --git a/solid-bold/index.html b/solid-bold/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-bold/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-bold/package.json b/solid-bold/package.json deleted file mode 100644 index 753ecdd5b9..0000000000 --- a/solid-bold/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-bold", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-bold/src/App.tsx b/solid-bold/src/App.tsx deleted file mode 100644 index 274955047d..0000000000 --- a/solid-bold/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/bold' - -export default function App() { - return -} diff --git a/solid-bold/src/app.css b/solid-bold/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-bold/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-bold/src/components/editor/examples/bold/editor.tsx b/solid-bold/src/components/editor/examples/bold/editor.tsx deleted file mode 100644 index b0fb2216a5..0000000000 --- a/solid-bold/src/components/editor/examples/bold/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-bold' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-bold/src/components/editor/examples/bold/extension.ts b/solid-bold/src/components/editor/examples/bold/extension.ts deleted file mode 100644 index eaa4fba721..0000000000 --- a/solid-bold/src/components/editor/examples/bold/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBold } from 'prosekit/extensions/bold' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBold(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-bold/src/components/editor/examples/bold/index.ts b/solid-bold/src/components/editor/examples/bold/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-bold/src/components/editor/examples/bold/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-bold/src/components/editor/sample/sample-doc-bold.ts b/solid-bold/src/components/editor/sample/sample-doc-bold.ts deleted file mode 100644 index 09ed08daad..0000000000 --- a/solid-bold/src/components/editor/sample/sample-doc-bold.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/solid-bold/src/components/editor/ui/button/button.tsx b/solid-bold/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-bold/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-bold/src/components/editor/ui/button/index.ts b/solid-bold/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-bold/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-bold/src/components/editor/ui/image-upload-popover/index.ts b/solid-bold/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-bold/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-bold/src/components/editor/ui/toolbar/index.ts b/solid-bold/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-bold/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-bold/src/components/editor/ui/toolbar/toolbar.tsx b/solid-bold/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-bold/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-bold/src/index.tsx b/solid-bold/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-bold/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-bold/tsconfig.app.json b/solid-bold/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-bold/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-bold/tsconfig.json b/solid-bold/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-bold/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-bold/tsconfig.node.json b/solid-bold/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-bold/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-bold/vite.config.ts b/solid-bold/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-bold/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-change-tracking/.gitignore b/solid-change-tracking/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-change-tracking/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-change-tracking/README.md b/solid-change-tracking/README.md deleted file mode 100644 index 1a4f29381a..0000000000 --- a/solid-change-tracking/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-change-tracking - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-change-tracking) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-change-tracking) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-change-tracking solid-change-tracking -cd solid-change-tracking -npm install -npm run dev -``` diff --git a/solid-change-tracking/index.html b/solid-change-tracking/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-change-tracking/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-change-tracking/package.json b/solid-change-tracking/package.json deleted file mode 100644 index bad9b72c6e..0000000000 --- a/solid-change-tracking/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-change-tracking", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-change-tracking/src/App.tsx b/solid-change-tracking/src/App.tsx deleted file mode 100644 index 88160e69c9..0000000000 --- a/solid-change-tracking/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/change-tracking' - -export default function App() { - return -} diff --git a/solid-change-tracking/src/app.css b/solid-change-tracking/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-change-tracking/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx b/solid-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx deleted file mode 100644 index 0d95a96575..0000000000 --- a/solid-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, union } from 'prosekit/core' -import { defineCommitViewer, type Commit } from 'prosekit/extensions/commit' -import { defineReadonly } from 'prosekit/extensions/readonly' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -export default function EditorDiff(props: { commit: Commit }): JSX.Element { - const extension = union( - defineBasicExtension(), - defineReadonly(), - defineCommitViewer(props.commit), - ) - const editor = createEditor({ extension }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx b/solid-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx deleted file mode 100644 index d05b604134..0000000000 --- a/solid-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, union, type NodeJSON } from 'prosekit/core' -import { - defineCommitRecorder, - type CommitRecorder, -} from 'prosekit/extensions/commit' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -export default function EditorMain(props: { - commitRecorder: CommitRecorder - initialContent?: NodeJSON -}): JSX.Element { - const extension = union( - defineBasicExtension(), - defineCommitRecorder(props.commitRecorder), - ) - const editor = createEditor({ - extension, - defaultContent: props.initialContent, - }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-change-tracking/src/components/editor/examples/change-tracking/editor.tsx b/solid-change-tracking/src/components/editor/examples/change-tracking/editor.tsx deleted file mode 100644 index 7a890490ef..0000000000 --- a/solid-change-tracking/src/components/editor/examples/change-tracking/editor.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import type { NodeJSON } from 'prosekit/core' -import { CommitRecorder, type Commit } from 'prosekit/extensions/commit' -import { createSignal, For, type JSX } from 'solid-js' - -import EditorDiff from './editor-diff' -import EditorMain from './editor-main' - -export default function Editor(): JSX.Element { - const [commits, setCommits] = createSignal< - { id: string; date: Date; commit: Commit }[] - >([]) - const [key, setKey] = createSignal(0) - const [initialContent, setInitialContent] = createSignal< - NodeJSON | undefined - >() - const commitRecorder = new CommitRecorder() - - const handleCommit = () => { - const commit = commitRecorder.commit() - if (!commit) return - const id = Math.random().toString(36).slice(2, 9) - setCommits((commits) => [{ id, date: new Date(), commit }, ...commits]) - } - - const handleRestore = (id: string) => { - const commitIndex = commits().findIndex((commit) => commit.id === id) - const commit = commits()[commitIndex] - if (commitIndex === -1 || !commit) return - const doc = commit.commit.doc - setInitialContent(doc) - setCommits((commits) => commits.slice(commitIndex)) - setKey((key) => key + 1) - } - - return ( -
-
-
- - {() => ( - - )} - -
- -
-
- - {(commit) => ( -
-
- -
-
- - {commit.date.toLocaleTimeString()} - - -
-
- )} -
-
-
- ) -} diff --git a/solid-change-tracking/src/components/editor/examples/change-tracking/index.ts b/solid-change-tracking/src/components/editor/examples/change-tracking/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-change-tracking/src/components/editor/examples/change-tracking/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-change-tracking/src/index.tsx b/solid-change-tracking/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-change-tracking/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-change-tracking/tsconfig.app.json b/solid-change-tracking/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-change-tracking/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-change-tracking/tsconfig.json b/solid-change-tracking/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-change-tracking/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-change-tracking/tsconfig.node.json b/solid-change-tracking/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-change-tracking/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-change-tracking/vite.config.ts b/solid-change-tracking/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-change-tracking/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-code-block-themes/.gitignore b/solid-code-block-themes/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-code-block-themes/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-code-block-themes/README.md b/solid-code-block-themes/README.md deleted file mode 100644 index d14681c4c5..0000000000 --- a/solid-code-block-themes/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-code-block-themes - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-code-block-themes) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-code-block-themes) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-code-block-themes solid-code-block-themes -cd solid-code-block-themes -npm install -npm run dev -``` diff --git a/solid-code-block-themes/index.html b/solid-code-block-themes/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-code-block-themes/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-code-block-themes/package.json b/solid-code-block-themes/package.json deleted file mode 100644 index 797e359d7c..0000000000 --- a/solid-code-block-themes/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-code-block-themes", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-code-block-themes/src/App.tsx b/solid-code-block-themes/src/App.tsx deleted file mode 100644 index 9b93464b4e..0000000000 --- a/solid-code-block-themes/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code-block-themes' - -export default function App() { - return -} diff --git a/solid-code-block-themes/src/app.css b/solid-code-block-themes/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-code-block-themes/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx b/solid-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx deleted file mode 100644 index efa2dcbb51..0000000000 --- a/solid-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-code-block' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/solid-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts deleted file mode 100644 index b5686b8c04..0000000000 --- a/solid-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union(defineBasicExtension(), defineCodeBlockView()) -} - -export type EditorExtension = ReturnType diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/solid-code-block-themes/src/components/editor/examples/code-block-themes/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-code-block-themes/src/components/editor/examples/code-block-themes/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx b/solid-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx deleted file mode 100644 index 63188073ca..0000000000 --- a/solid-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { - defineCodeBlockShiki, - shikiBundledThemesInfo, - type ShikiBundledTheme, -} from 'prosekit/extensions/code-block' -import { useExtension } from 'prosekit/solid' -import { createMemo, createSignal, For, type JSX } from 'solid-js' - -export function ThemeSelector(): JSX.Element { - const [theme, setTheme] = createSignal('github-dark') - const extension = createMemo(() => { - return defineCodeBlockShiki({ themes: [theme() as ShikiBundledTheme] }) - }) - useExtension(extension) - - return ( - <> - - - - ) -} diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx b/solid-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx deleted file mode 100644 index 7fc735f1d1..0000000000 --- a/solid-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import type { JSX } from 'solid-js' - -import { ThemeSelector } from './theme-selector' - -export default function Toolbar(): JSX.Element { - return ( -
- -
- ) -} diff --git a/solid-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/solid-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/solid-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/solid-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx b/solid-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index 2d67b563f7..0000000000 --- a/solid-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { SolidNodeViewProps } from 'prosekit/solid' -import { For, type JSX } from 'solid-js' - -export default function CodeBlockView(props: SolidNodeViewProps): JSX.Element { - const attrs = () => props.node.attrs as CodeBlockAttrs - const language = () => attrs().language - - const setLanguage = (lang: string) => { - const newAttrs: CodeBlockAttrs = { language: lang } - props.setAttrs(newAttrs) - } - - return ( - <> - -

-    
-  )
-}
diff --git a/solid-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/solid-code-block-themes/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index 50bbbea7df..0000000000
--- a/solid-code-block-themes/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSolidNodeView,
-  type SolidNodeViewComponent,
-} from 'prosekit/solid'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineSolidNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies SolidNodeViewComponent,
-  })
-}
diff --git a/solid-code-block-themes/src/index.tsx b/solid-code-block-themes/src/index.tsx
deleted file mode 100644
index 92b7740757..0000000000
--- a/solid-code-block-themes/src/index.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-/* @refresh reload */
-import './app.css'
-import { render } from 'solid-js/web'
-import App from './App'
-
-const root = document.getElementById('root')
-
-render(() => , root!)
diff --git a/solid-code-block-themes/tsconfig.app.json b/solid-code-block-themes/tsconfig.app.json
deleted file mode 100644
index c0b480e758..0000000000
--- a/solid-code-block-themes/tsconfig.app.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
-    "target": "ES2022",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "lib": ["ES2022", "DOM", "DOM.Iterable"],
-    "types": ["vite/client"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-    "jsx": "preserve",
-    "jsxImportSource": "solid-js",
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["src"]
-}
diff --git a/solid-code-block-themes/tsconfig.json b/solid-code-block-themes/tsconfig.json
deleted file mode 100644
index 1ffef600d9..0000000000
--- a/solid-code-block-themes/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "files": [],
-  "references": [
-    { "path": "./tsconfig.app.json" },
-    { "path": "./tsconfig.node.json" }
-  ]
-}
diff --git a/solid-code-block-themes/tsconfig.node.json b/solid-code-block-themes/tsconfig.node.json
deleted file mode 100644
index 8a67f62f4c..0000000000
--- a/solid-code-block-themes/tsconfig.node.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
-    "target": "ES2023",
-    "lib": ["ES2023"],
-    "module": "ESNext",
-    "types": ["node"],
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/solid-code-block-themes/vite.config.ts b/solid-code-block-themes/vite.config.ts
deleted file mode 100644
index 9cb3cb51fd..0000000000
--- a/solid-code-block-themes/vite.config.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { defineConfig } from 'vite'
-import solid from 'vite-plugin-solid'
-import tailwindcss from '@tailwindcss/vite'
-
-export default defineConfig({
-  plugins: [solid(), tailwindcss()],
-})
diff --git a/solid-code-block/.gitignore b/solid-code-block/.gitignore
deleted file mode 100644
index 5d6225c6df..0000000000
--- a/solid-code-block/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-dist
-.next
-.svelte-kit
diff --git a/solid-code-block/README.md b/solid-code-block/README.md
deleted file mode 100644
index afa9c05889..0000000000
--- a/solid-code-block/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# solid-code-block
-
-A [ProseKit](https://prosekit.dev) example.
-
-[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-code-block)
-[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-code-block)
-
-Run the example locally with:
-
-```bash
-npx degit prosekit/examples/solid-code-block solid-code-block
-cd solid-code-block
-npm install
-npm run dev
-```
diff --git a/solid-code-block/index.html b/solid-code-block/index.html
deleted file mode 100644
index 375ea8dbc4..0000000000
--- a/solid-code-block/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-  
-    
-    
-    ProseKit + Solid
-  
-  
-    
- - - diff --git a/solid-code-block/package.json b/solid-code-block/package.json deleted file mode 100644 index a2ab09f621..0000000000 --- a/solid-code-block/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-code-block", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-code-block/src/App.tsx b/solid-code-block/src/App.tsx deleted file mode 100644 index 961ce70aad..0000000000 --- a/solid-code-block/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code-block' - -export default function App() { - return -} diff --git a/solid-code-block/src/app.css b/solid-code-block/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-code-block/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-code-block/src/components/editor/examples/code-block/editor.tsx b/solid-code-block/src/components/editor/examples/code-block/editor.tsx deleted file mode 100644 index b989b65867..0000000000 --- a/solid-code-block/src/components/editor/examples/code-block/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-code-block' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-code-block/src/components/editor/examples/code-block/extension.ts b/solid-code-block/src/components/editor/examples/code-block/extension.ts deleted file mode 100644 index 099cacf03b..0000000000 --- a/solid-code-block/src/components/editor/examples/code-block/extension.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { - defineCodeBlock, - defineCodeBlockShiki, -} from 'prosekit/extensions/code-block' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCodeBlock(), - defineCodeBlockShiki(), - defineCodeBlockView(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-code-block/src/components/editor/examples/code-block/index.ts b/solid-code-block/src/components/editor/examples/code-block/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-code-block/src/components/editor/examples/code-block/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-code-block/src/components/editor/sample/sample-doc-code-block.ts b/solid-code-block/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/solid-code-block/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/solid-code-block/src/components/editor/ui/button/button.tsx b/solid-code-block/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-code-block/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-code-block/src/components/editor/ui/button/index.ts b/solid-code-block/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-code-block/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx b/solid-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index 2d67b563f7..0000000000 --- a/solid-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { SolidNodeViewProps } from 'prosekit/solid' -import { For, type JSX } from 'solid-js' - -export default function CodeBlockView(props: SolidNodeViewProps): JSX.Element { - const attrs = () => props.node.attrs as CodeBlockAttrs - const language = () => attrs().language - - const setLanguage = (lang: string) => { - const newAttrs: CodeBlockAttrs = { language: lang } - props.setAttrs(newAttrs) - } - - return ( - <> - -

-    
-  )
-}
diff --git a/solid-code-block/src/components/editor/ui/code-block-view/index.ts b/solid-code-block/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index 50bbbea7df..0000000000
--- a/solid-code-block/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSolidNodeView,
-  type SolidNodeViewComponent,
-} from 'prosekit/solid'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineSolidNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies SolidNodeViewComponent,
-  })
-}
diff --git a/solid-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
deleted file mode 100644
index efa306305f..0000000000
--- a/solid-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-import type { Uploader } from 'prosekit/extensions/file'
-import type { ImageExtension } from 'prosekit/extensions/image'
-import { useEditor } from 'prosekit/solid'
-import {
-  PopoverPopup,
-  PopoverPositioner,
-  PopoverRoot,
-  PopoverTrigger,
-} from 'prosekit/solid/popover'
-import type { OpenChangeEvent } from 'prosekit/web/popover'
-import { createSignal, createUniqueId, Show, type JSX } from 'solid-js'
-
-import { Button } from '../button'
-
-export default function ImageUploadPopover(props: {
-  uploader: Uploader
-  tooltip: string
-  disabled: boolean
-  children: JSX.Element
-}): JSX.Element {
-  const [open, setOpen] = createSignal(false)
-  const [url, setUrl] = createSignal('')
-  const [file, setFile] = createSignal(null)
-  const ariaId = createUniqueId()
-
-  const editor = useEditor()
-
-  const handleFileChange = (event: Event) => {
-    const target = event.target as HTMLInputElement
-    const selectedFile = target.files?.[0]
-
-    if (selectedFile) {
-      setFile(selectedFile)
-      setUrl('')
-    } else {
-      setFile(null)
-    }
-  }
-
-  const handleUrlChange = (event: Event) => {
-    const target = event.target as HTMLInputElement
-    const inputUrl = target.value
-
-    if (inputUrl) {
-      setUrl(inputUrl)
-      setFile(null)
-    } else {
-      setUrl('')
-    }
-  }
-
-  const deferResetState = () => {
-    setTimeout(() => {
-      setUrl('')
-      setFile(null)
-    }, 300)
-  }
-
-  const handleSubmit = () => {
-    if (url()) {
-      editor().commands.insertImage({ src: url() })
-    } else if (file()) {
-      editor().commands.uploadImage({ file: file()!, uploader: props.uploader })
-    }
-    setOpen(false)
-    deferResetState()
-  }
-
-  const handleOpenChange = (event: OpenChangeEvent) => {
-    if (!event.detail) {
-      deferResetState()
-    }
-    setOpen(event.detail)
-  }
-
-  return (
-    
-      
-        
-      
-
-      
-        
-          
-            
-            
-          
-
-          
-            
-            
-          
-
-          
-            
-          
-
-          
-            
-          
-        
-      
-    
-  )
-}
diff --git a/solid-code-block/src/components/editor/ui/image-upload-popover/index.ts b/solid-code-block/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index 5d49d873ce..0000000000
--- a/solid-code-block/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/solid-code-block/src/components/editor/ui/toolbar/index.ts b/solid-code-block/src/components/editor/ui/toolbar/index.ts
deleted file mode 100644
index fdf6741e6a..0000000000
--- a/solid-code-block/src/components/editor/ui/toolbar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as Toolbar } from './toolbar'
diff --git a/solid-code-block/src/components/editor/ui/toolbar/toolbar.tsx b/solid-code-block/src/components/editor/ui/toolbar/toolbar.tsx
deleted file mode 100644
index ee3858791a..0000000000
--- a/solid-code-block/src/components/editor/ui/toolbar/toolbar.tsx
+++ /dev/null
@@ -1,406 +0,0 @@
-import type { BasicExtension } from 'prosekit/basic'
-import type { Editor } from 'prosekit/core'
-import type { Uploader } from 'prosekit/extensions/file'
-import { useEditorDerivedValue } from 'prosekit/solid'
-import { Show, type JSX } from 'solid-js'
-
-import { Button } from '../button'
-import { ImageUploadPopover } from '../image-upload-popover'
-
-function getToolbarItems(editor: Editor) {
-  return {
-    undo: editor.commands.undo
-      ? {
-          isActive: false,
-          canExec: editor.commands.undo.canExec(),
-          command: () => editor.commands.undo(),
-        }
-      : undefined,
-    redo: editor.commands.redo
-      ? {
-          isActive: false,
-          canExec: editor.commands.redo.canExec(),
-          command: () => editor.commands.redo(),
-        }
-      : undefined,
-    bold: editor.commands.toggleBold
-      ? {
-          isActive: editor.marks.bold.isActive(),
-          canExec: editor.commands.toggleBold.canExec(),
-          command: () => editor.commands.toggleBold(),
-        }
-      : undefined,
-    italic: editor.commands.toggleItalic
-      ? {
-          isActive: editor.marks.italic.isActive(),
-          canExec: editor.commands.toggleItalic.canExec(),
-          command: () => editor.commands.toggleItalic(),
-        }
-      : undefined,
-    underline: editor.commands.toggleUnderline
-      ? {
-          isActive: editor.marks.underline.isActive(),
-          canExec: editor.commands.toggleUnderline.canExec(),
-          command: () => editor.commands.toggleUnderline(),
-        }
-      : undefined,
-    strike: editor.commands.toggleStrike
-      ? {
-          isActive: editor.marks.strike.isActive(),
-          canExec: editor.commands.toggleStrike.canExec(),
-          command: () => editor.commands.toggleStrike(),
-        }
-      : undefined,
-    code: editor.commands.toggleCode
-      ? {
-          isActive: editor.marks.code.isActive(),
-          canExec: editor.commands.toggleCode.canExec(),
-          command: () => editor.commands.toggleCode(),
-        }
-      : undefined,
-    codeBlock: editor.commands.insertCodeBlock
-      ? {
-          isActive: editor.nodes.codeBlock.isActive(),
-          canExec: editor.commands.insertCodeBlock.canExec({
-            language: 'javascript',
-          }),
-          command: () =>
-            editor.commands.insertCodeBlock({ language: 'javascript' }),
-        }
-      : undefined,
-    heading1: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 1 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 1 }),
-          command: () => editor.commands.toggleHeading({ level: 1 }),
-        }
-      : undefined,
-    heading2: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 2 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 2 }),
-          command: () => editor.commands.toggleHeading({ level: 2 }),
-        }
-      : undefined,
-    heading3: editor.commands.toggleHeading
-      ? {
-          isActive: editor.nodes.heading.isActive({ level: 3 }),
-          canExec: editor.commands.toggleHeading.canExec({ level: 3 }),
-          command: () => editor.commands.toggleHeading({ level: 3 }),
-        }
-      : undefined,
-    horizontalRule: editor.commands.insertHorizontalRule
-      ? {
-          isActive: editor.nodes.horizontalRule.isActive(),
-          canExec: editor.commands.insertHorizontalRule.canExec(),
-          command: () => editor.commands.insertHorizontalRule(),
-        }
-      : undefined,
-    blockquote: editor.commands.toggleBlockquote
-      ? {
-          isActive: editor.nodes.blockquote.isActive(),
-          canExec: editor.commands.toggleBlockquote.canExec(),
-          command: () => editor.commands.toggleBlockquote(),
-        }
-      : undefined,
-    bulletList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'bullet' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }),
-          command: () => editor.commands.toggleList({ kind: 'bullet' }),
-        }
-      : undefined,
-    orderedList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'ordered' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }),
-          command: () => editor.commands.toggleList({ kind: 'ordered' }),
-        }
-      : undefined,
-    taskList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'task' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'task' }),
-          command: () => editor.commands.toggleList({ kind: 'task' }),
-        }
-      : undefined,
-    toggleList: editor.commands.toggleList
-      ? {
-          isActive: editor.nodes.list.isActive({ kind: 'toggle' }),
-          canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }),
-          command: () => editor.commands.toggleList({ kind: 'toggle' }),
-        }
-      : undefined,
-    indentList: editor.commands.indentList
-      ? {
-          isActive: false,
-          canExec: editor.commands.indentList.canExec(),
-          command: () => editor.commands.indentList(),
-        }
-      : undefined,
-    dedentList: editor.commands.dedentList
-      ? {
-          isActive: false,
-          canExec: editor.commands.dedentList.canExec(),
-          command: () => editor.commands.dedentList(),
-        }
-      : undefined,
-    insertImage: editor.commands.insertImage
-      ? {
-          isActive: false,
-          canExec: editor.commands.insertImage.canExec(),
-        }
-      : undefined,
-  }
-}
-
-export default function Toolbar(props: {
-  uploader?: Uploader
-}): JSX.Element {
-  const items = useEditorDerivedValue(getToolbarItems)
-
-  return (
-    
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-code-block/src/index.tsx b/solid-code-block/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-code-block/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-code-block/tsconfig.app.json b/solid-code-block/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-code-block/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-code-block/tsconfig.json b/solid-code-block/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-code-block/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-code-block/tsconfig.node.json b/solid-code-block/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-code-block/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-code-block/vite.config.ts b/solid-code-block/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-code-block/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-code/.gitignore b/solid-code/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-code/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-code/README.md b/solid-code/README.md deleted file mode 100644 index 39c8ebbc11..0000000000 --- a/solid-code/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-code - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-code) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-code) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-code solid-code -cd solid-code -npm install -npm run dev -``` diff --git a/solid-code/index.html b/solid-code/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-code/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-code/package.json b/solid-code/package.json deleted file mode 100644 index 248c1274f4..0000000000 --- a/solid-code/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-code", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-code/src/App.tsx b/solid-code/src/App.tsx deleted file mode 100644 index f2f5d9a360..0000000000 --- a/solid-code/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/code' - -export default function App() { - return -} diff --git a/solid-code/src/app.css b/solid-code/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-code/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-code/src/components/editor/examples/code/editor.tsx b/solid-code/src/components/editor/examples/code/editor.tsx deleted file mode 100644 index 664f3bb7ee..0000000000 --- a/solid-code/src/components/editor/examples/code/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-code' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-code/src/components/editor/examples/code/extension.ts b/solid-code/src/components/editor/examples/code/extension.ts deleted file mode 100644 index e9e273216e..0000000000 --- a/solid-code/src/components/editor/examples/code/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCode(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-code/src/components/editor/examples/code/index.ts b/solid-code/src/components/editor/examples/code/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-code/src/components/editor/examples/code/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-code/src/components/editor/sample/sample-doc-code.ts b/solid-code/src/components/editor/sample/sample-doc-code.ts deleted file mode 100644 index 2fdbcee1f3..0000000000 --- a/solid-code/src/components/editor/sample/sample-doc-code.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'This is code', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/solid-code/src/components/editor/ui/button/button.tsx b/solid-code/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-code/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-code/src/components/editor/ui/button/index.ts b/solid-code/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-code/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-code/src/components/editor/ui/image-upload-popover/index.ts b/solid-code/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-code/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-code/src/components/editor/ui/toolbar/index.ts b/solid-code/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-code/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-code/src/components/editor/ui/toolbar/toolbar.tsx b/solid-code/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-code/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-code/src/index.tsx b/solid-code/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-code/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-code/tsconfig.app.json b/solid-code/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-code/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-code/tsconfig.json b/solid-code/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-code/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-code/tsconfig.node.json b/solid-code/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-code/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-code/vite.config.ts b/solid-code/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-code/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-drop-cursor/.gitignore b/solid-drop-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-drop-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-drop-cursor/README.md b/solid-drop-cursor/README.md deleted file mode 100644 index 747d97ef31..0000000000 --- a/solid-drop-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-drop-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-drop-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-drop-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-drop-cursor solid-drop-cursor -cd solid-drop-cursor -npm install -npm run dev -``` diff --git a/solid-drop-cursor/index.html b/solid-drop-cursor/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-drop-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-drop-cursor/package.json b/solid-drop-cursor/package.json deleted file mode 100644 index b362ad4e72..0000000000 --- a/solid-drop-cursor/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-drop-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-drop-cursor/src/App.tsx b/solid-drop-cursor/src/App.tsx deleted file mode 100644 index f66459b286..0000000000 --- a/solid-drop-cursor/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/drop-cursor' - -export default function App() { - return -} diff --git a/solid-drop-cursor/src/app.css b/solid-drop-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-drop-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx b/solid-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx deleted file mode 100644 index efcf2d16b5..0000000000 --- a/solid-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-drop-cursor' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/solid-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts deleted file mode 100644 index fd79a2c96c..0000000000 --- a/solid-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineImage(), - defineDropCursor({ - color: false, - width: 4, - class: 'transition-all bg-blue-500', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/solid-drop-cursor/src/components/editor/examples/drop-cursor/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-drop-cursor/src/components/editor/examples/drop-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/solid-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts deleted file mode 100644 index 22c6b93465..0000000000 --- a/solid-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the images below to see the custom drop cursor.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/320x240/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/green/320x240/40', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blue/320x240/187', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/red/320x240/188', - }, - }, - ], -} diff --git a/solid-drop-cursor/src/index.tsx b/solid-drop-cursor/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-drop-cursor/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-drop-cursor/tsconfig.app.json b/solid-drop-cursor/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-drop-cursor/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-drop-cursor/tsconfig.json b/solid-drop-cursor/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-drop-cursor/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-drop-cursor/tsconfig.node.json b/solid-drop-cursor/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-drop-cursor/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-drop-cursor/vite.config.ts b/solid-drop-cursor/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-drop-cursor/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-emoji-rules/.gitignore b/solid-emoji-rules/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-emoji-rules/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-emoji-rules/README.md b/solid-emoji-rules/README.md deleted file mode 100644 index 6c7a5fdda3..0000000000 --- a/solid-emoji-rules/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-emoji-rules - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-emoji-rules) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-emoji-rules) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-emoji-rules solid-emoji-rules -cd solid-emoji-rules -npm install -npm run dev -``` diff --git a/solid-emoji-rules/index.html b/solid-emoji-rules/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-emoji-rules/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-emoji-rules/package.json b/solid-emoji-rules/package.json deleted file mode 100644 index b780036fa9..0000000000 --- a/solid-emoji-rules/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-emoji-rules", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-emoji-rules/src/App.tsx b/solid-emoji-rules/src/App.tsx deleted file mode 100644 index 1e4ef54fd6..0000000000 --- a/solid-emoji-rules/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/emoji-rules' - -export default function App() { - return -} diff --git a/solid-emoji-rules/src/app.css b/solid-emoji-rules/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-emoji-rules/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx b/solid-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx deleted file mode 100644 index 6f695978e8..0000000000 --- a/solid-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { defineExtension } from './extension' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/solid-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts deleted file mode 100644 index 5cac9cbc79..0000000000 --- a/solid-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineEnterRule } from 'prosekit/extensions/enter-rule' - -/** - * Converts the text before the text cursor into an emoji when pressing `Enter`. - */ -export function defineEmojiEnterRule() { - return defineEnterRule({ - regex: /:(apple|banana):$/, - handler: ({ match, from, to, state }) => { - const text = match[1] as 'apple' | 'banana' - const emoji = text === 'apple' ? '🍎' : '🍌' - return state.tr.replaceWith(from, to, state.schema.text(emoji)) - }, - }) -} diff --git a/solid-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/solid-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts deleted file mode 100644 index bc9bcb8412..0000000000 --- a/solid-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { defineEmojiEnterRule } from './emoji' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineEmojiEnterRule(), - definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/solid-emoji-rules/src/components/editor/examples/emoji-rules/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-emoji-rules/src/components/editor/examples/emoji-rules/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-emoji-rules/src/index.tsx b/solid-emoji-rules/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-emoji-rules/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-emoji-rules/tsconfig.app.json b/solid-emoji-rules/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-emoji-rules/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-emoji-rules/tsconfig.json b/solid-emoji-rules/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-emoji-rules/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-emoji-rules/tsconfig.node.json b/solid-emoji-rules/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-emoji-rules/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-emoji-rules/vite.config.ts b/solid-emoji-rules/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-emoji-rules/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-full/.gitignore b/solid-full/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-full/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-full/README.md b/solid-full/README.md deleted file mode 100644 index 063b56d28a..0000000000 --- a/solid-full/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-full - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-full) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-full) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-full solid-full -cd solid-full -npm install -npm run dev -``` diff --git a/solid-full/index.html b/solid-full/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-full/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-full/package.json b/solid-full/package.json deleted file mode 100644 index edf5d9782d..0000000000 --- a/solid-full/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-solid-full", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-full/src/App.tsx b/solid-full/src/App.tsx deleted file mode 100644 index c93bd3a429..0000000000 --- a/solid-full/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/full' - -export default function App() { - return -} diff --git a/solid-full/src/app.css b/solid-full/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-full/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-full/src/components/editor/examples/full/editor.tsx b/solid-full/src/components/editor/examples/full/editor.tsx deleted file mode 100644 index 8f158cfa67..0000000000 --- a/solid-full/src/components/editor/examples/full/editor.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-full' -import { tags } from '../../sample/sample-tag-data' -import { sampleUploader } from '../../sample/sample-uploader' -import { users } from '../../sample/sample-user-data' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' -import { InlineMenu } from '../../ui/inline-menu' -import { SlashMenu } from '../../ui/slash-menu' -import { TableHandle } from '../../ui/table-handle' -import { TagMenu } from '../../ui/tag-menu' -import { Toolbar } from '../../ui/toolbar' -import { UserMenu } from '../../ui/user-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
- - - - - - - -
-
-
- ) -} diff --git a/solid-full/src/components/editor/examples/full/extension.ts b/solid-full/src/components/editor/examples/full/extension.ts deleted file mode 100644 index 5fc2f60685..0000000000 --- a/solid-full/src/components/editor/examples/full/extension.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineImageUploadHandler } from 'prosekit/extensions/image' -import { defineMath } from 'prosekit/extensions/math' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' -import { sampleUploader } from '../../sample/sample-uploader' -import { defineCodeBlockView } from '../../ui/code-block-view' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - defineMention(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - defineCodeBlockShiki(), - defineHorizontalRule(), - defineCodeBlockView(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-full/src/components/editor/examples/full/index.ts b/solid-full/src/components/editor/examples/full/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-full/src/components/editor/examples/full/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-full/src/components/editor/sample/katex.ts b/solid-full/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/solid-full/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/solid-full/src/components/editor/sample/sample-doc-full.ts b/solid-full/src/components/editor/sample/sample-doc-full.ts deleted file mode 100644 index 13e49b634d..0000000000 --- a/solid-full/src/components/editor/sample/sample-doc-full.ts +++ /dev/null @@ -1,442 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'The editor that thinks like you' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', - }, - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'writing without barriers', - }, - { type: 'text', text: '.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Text that shines.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Make your words ' }, - { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, - { type: 'text', text: ', or ' }, - { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, - { type: 'text', text: '. Add ' }, - { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, - { type: 'text', text: ' that stands out. Create ' }, - { - type: 'text', - marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], - text: 'links', - }, - { type: 'text', text: ' that connect.' }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Select any text to format it. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '@' }, - { type: 'text', text: ' to mention ' }, - { - type: 'mention', - attrs: { id: '39', value: '@someone', kind: 'user' }, - }, - { type: 'text', text: ' or ' }, - { type: 'text', marks: [{ type: 'code' }], text: '#' }, - { type: 'text', text: ' for ' }, - { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, - { type: 'text', text: '. Press ' }, - { type: 'text', marks: [{ type: 'code' }], text: '/' }, - { type: 'text', text: " and discover what's possible." }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Lists that organize.' }], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Bullet points that guide thoughts' }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Nested lists for complex ideas' }], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sub-points flow naturally' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Tasks that focus' }], - }, - { - type: 'list', - attrs: { kind: 'task', order: null, checked: true, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Done feels good' }], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Todo drives action' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Numbered steps' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sequential thinking' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Clear progress' }], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Code that inspires.' }], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Images that captivate.' }], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/season/320x240/107', - }, - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the handle in the bottom right corner to resize.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Tables that structure.' }], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'Feature', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'How to use', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Format text' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Select and choose' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Perfect styling' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Add mentions' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Type @ and name' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Connected ideas' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Insert anything' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Press / for menu' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Endless possibilities' }], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Math that renders.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Inline math like ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' appears within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Quotes that inspire.' }], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: '"This is not just an editor. This is how writing should feel."', - }, - ], - }, - ], - }, - { type: 'horizontalRule' }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Start typing. Everything else just flows.' }, - ], - }, - ], -} diff --git a/solid-full/src/components/editor/sample/sample-tag-data.ts b/solid-full/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/solid-full/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/solid-full/src/components/editor/sample/sample-uploader.ts b/solid-full/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/solid-full/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/solid-full/src/components/editor/sample/sample-user-data.ts b/solid-full/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/solid-full/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/solid-full/src/components/editor/ui/block-handle/block-handle.tsx b/solid-full/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 95e1693ef6..0000000000 --- a/solid-full/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/solid/block-handle' -import type { JSX } from 'solid-js' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props): JSX.Element { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/solid-full/src/components/editor/ui/block-handle/index.ts b/solid-full/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/solid-full/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/solid-full/src/components/editor/ui/button/button.tsx b/solid-full/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-full/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-full/src/components/editor/ui/button/index.ts b/solid-full/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-full/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-full/src/components/editor/ui/code-block-view/code-block-view.tsx b/solid-full/src/components/editor/ui/code-block-view/code-block-view.tsx deleted file mode 100644 index 2d67b563f7..0000000000 --- a/solid-full/src/components/editor/ui/code-block-view/code-block-view.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' -import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' -import type { SolidNodeViewProps } from 'prosekit/solid' -import { For, type JSX } from 'solid-js' - -export default function CodeBlockView(props: SolidNodeViewProps): JSX.Element { - const attrs = () => props.node.attrs as CodeBlockAttrs - const language = () => attrs().language - - const setLanguage = (lang: string) => { - const newAttrs: CodeBlockAttrs = { language: lang } - props.setAttrs(newAttrs) - } - - return ( - <> - -

-    
-  )
-}
diff --git a/solid-full/src/components/editor/ui/code-block-view/index.ts b/solid-full/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index 50bbbea7df..0000000000
--- a/solid-full/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSolidNodeView,
-  type SolidNodeViewComponent,
-} from 'prosekit/solid'
-
-import CodeBlockView from './code-block-view'
-
-export function defineCodeBlockView(): Extension {
-  return defineSolidNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView satisfies SolidNodeViewComponent,
-  })
-}
diff --git a/solid-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/solid-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
deleted file mode 100644
index c5a24c7faa..0000000000
--- a/solid-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import { DropIndicator as BaseDropIndicator } from 'prosekit/solid/drop-indicator'
-import type { JSX } from 'solid-js'
-
-export default function DropIndicator(): JSX.Element {
-  return 
-}
diff --git a/solid-full/src/components/editor/ui/drop-indicator/index.ts b/solid-full/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index f8fb7139c4..0000000000
--- a/solid-full/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator'
diff --git a/solid-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
deleted file mode 100644
index efa306305f..0000000000
--- a/solid-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-import type { Uploader } from 'prosekit/extensions/file'
-import type { ImageExtension } from 'prosekit/extensions/image'
-import { useEditor } from 'prosekit/solid'
-import {
-  PopoverPopup,
-  PopoverPositioner,
-  PopoverRoot,
-  PopoverTrigger,
-} from 'prosekit/solid/popover'
-import type { OpenChangeEvent } from 'prosekit/web/popover'
-import { createSignal, createUniqueId, Show, type JSX } from 'solid-js'
-
-import { Button } from '../button'
-
-export default function ImageUploadPopover(props: {
-  uploader: Uploader
-  tooltip: string
-  disabled: boolean
-  children: JSX.Element
-}): JSX.Element {
-  const [open, setOpen] = createSignal(false)
-  const [url, setUrl] = createSignal('')
-  const [file, setFile] = createSignal(null)
-  const ariaId = createUniqueId()
-
-  const editor = useEditor()
-
-  const handleFileChange = (event: Event) => {
-    const target = event.target as HTMLInputElement
-    const selectedFile = target.files?.[0]
-
-    if (selectedFile) {
-      setFile(selectedFile)
-      setUrl('')
-    } else {
-      setFile(null)
-    }
-  }
-
-  const handleUrlChange = (event: Event) => {
-    const target = event.target as HTMLInputElement
-    const inputUrl = target.value
-
-    if (inputUrl) {
-      setUrl(inputUrl)
-      setFile(null)
-    } else {
-      setUrl('')
-    }
-  }
-
-  const deferResetState = () => {
-    setTimeout(() => {
-      setUrl('')
-      setFile(null)
-    }, 300)
-  }
-
-  const handleSubmit = () => {
-    if (url()) {
-      editor().commands.insertImage({ src: url() })
-    } else if (file()) {
-      editor().commands.uploadImage({ file: file()!, uploader: props.uploader })
-    }
-    setOpen(false)
-    deferResetState()
-  }
-
-  const handleOpenChange = (event: OpenChangeEvent) => {
-    if (!event.detail) {
-      deferResetState()
-    }
-    setOpen(event.detail)
-  }
-
-  return (
-    
-      
-        
-      
-
-      
-        
-          
-            
-            
-          
-
-          
-            
-            
-          
-
-          
-            
-          
-
-          
-            
-          
-        
-      
-    
-  )
-}
diff --git a/solid-full/src/components/editor/ui/image-upload-popover/index.ts b/solid-full/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index 5d49d873ce..0000000000
--- a/solid-full/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/solid-full/src/components/editor/ui/image-view/image-view.tsx b/solid-full/src/components/editor/ui/image-view/image-view.tsx
deleted file mode 100644
index 813fbec79c..0000000000
--- a/solid-full/src/components/editor/ui/image-view/image-view.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import { UploadTask } from 'prosekit/extensions/file'
-import type { ImageAttrs } from 'prosekit/extensions/image'
-import type { SolidNodeViewProps } from 'prosekit/solid'
-import { ResizableHandle, ResizableRoot } from 'prosekit/solid/resizable'
-import { createEffect, createSignal, onCleanup, Show, type JSX } from 'solid-js'
-
-export default function ImageView(props: SolidNodeViewProps): JSX.Element {
-  const attrs = () => props.node.attrs as ImageAttrs
-  const url = () => attrs().src || ''
-  const uploading = () => url().startsWith('blob:')
-
-  const [aspectRatio, setAspectRatio] = createSignal()
-  const [error, setError] = createSignal()
-  const [progress, setProgress] = createSignal(0)
-
-  createEffect(() => {
-    if (!uploading()) return
-
-    const uploadTask = UploadTask.get(url())
-    if (!uploadTask) return
-
-    let canceled = false
-
-    uploadTask.finished.catch((err) => {
-      if (canceled) return
-      setError(String(err))
-    })
-    const unsubscribeProgress = uploadTask.subscribeProgress(
-      ({ loaded, total }) => {
-        if (canceled) return
-        setProgress(total ? loaded / total : 0)
-      },
-    )
-
-    onCleanup(() => {
-      canceled = true
-      unsubscribeProgress()
-    })
-  })
-
-  const handleImageLoad = (event: Event) => {
-    const img = event.target as HTMLImageElement
-    const { naturalWidth, naturalHeight } = img
-    const ratio = naturalWidth / naturalHeight
-    if (ratio && Number.isFinite(ratio)) {
-      setAspectRatio(ratio)
-    }
-    if (naturalWidth && naturalHeight && (!attrs().width || !attrs().height)) {
-      props.setAttrs({ width: naturalWidth, height: naturalHeight })
-    }
-  }
-
-  return (
-     props.setAttrs(event.detail)}
-      attr:data-selected={props.selected ? '' : undefined}
-      class="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid"
-    >
-      
-        upload preview
-      
-      
-        
-
-
{Math.round(progress() * 100)}%
-
-
- -
-
- -
-
- -
-
-
- ) -} diff --git a/solid-full/src/components/editor/ui/image-view/index.ts b/solid-full/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index 223c959559..0000000000 --- a/solid-full/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - defineSolidNodeView, - type SolidNodeViewComponent, -} from 'prosekit/solid' - -import ImageView from './image-view' - -export function defineImageView(): Extension { - return defineSolidNodeView({ - name: 'image', - component: ImageView satisfies SolidNodeViewComponent, - }) -} diff --git a/solid-full/src/components/editor/ui/inline-menu/index.ts b/solid-full/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/solid-full/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/solid-full/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-full/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index d61df6d794..0000000000 --- a/solid-full/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/solid' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/solid/inline-popover' -import { createSignal, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu(): JSX.Element { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor().commands.addLink({ href }) - } else { - editor().commands.removeLink() - } - - setLinkMenuOpen(false) - editor().focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - - - - {(item) => ( - setLinkMenuOpen(event.detail)} - > - - - -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
-
- - - -
-
-
- )} -
- - ) -} diff --git a/solid-full/src/components/editor/ui/slash-menu/index.ts b/solid-full/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/solid-full/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/solid-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/solid-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index aae5f3dc6b..0000000000 --- a/solid-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { AutocompleteEmpty } from 'prosekit/solid/autocomplete' -import type { JSX } from 'solid-js' - -export default function SlashMenuEmpty(): JSX.Element { - return ( - - No results - - ) -} diff --git a/solid-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/solid-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 9d8101d019..0000000000 --- a/solid-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { AutocompleteItem } from 'prosekit/solid/autocomplete' -import { Show, type JSX } from 'solid-js' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}): JSX.Element { - return ( - - {props.label} - - - {props.kbd} - - - - ) -} diff --git a/solid-full/src/components/editor/ui/slash-menu/slash-menu.tsx b/solid-full/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index c7090d7f36..0000000000 --- a/solid-full/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/solid' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/solid/autocomplete' -import type { JSX } from 'solid-js' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor().commands.setParagraph()} - /> - - editor().commands.setHeading({ level: 1 })} - /> - - editor().commands.setHeading({ level: 2 })} - /> - - editor().commands.setHeading({ level: 3 })} - /> - - editor().commands.wrapInList({ kind: 'bullet' })} - /> - - editor().commands.wrapInList({ kind: 'ordered' })} - /> - - editor().commands.wrapInList({ kind: 'task' })} - /> - - editor().commands.wrapInList({ kind: 'toggle' })} - /> - - editor().commands.setBlockquote()} - /> - - editor().commands.insertTable({ row: 3, col: 3 })} - /> - - editor().commands.insertHorizontalRule()} - /> - - editor().commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/solid-full/src/components/editor/ui/table-handle/index.ts b/solid-full/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/solid-full/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/solid-full/src/components/editor/ui/table-handle/table-handle.tsx b/solid-full/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index 463f4d3657..0000000000 --- a/solid-full/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/solid' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/solid/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/solid/table-handle' -import { Show, type JSX } from 'solid-js' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props): JSX.Element { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - - state().addTableColumnBefore.command()} - > - Insert Left - - - - state().addTableColumnAfter.command()} - > - Insert Right - - - - state().deleteCellSelection.command()} - > - Clear Contents - - Del - - - - - state().deleteTableColumn.command()} - > - Delete Column - - - - state().deleteTable.command()} - > - Delete Table - - - - -
-
-
- - - - -
-
- - - - state().addTableRowAbove.command()} - > - Insert Above - - - - state().addTableRowBelow.command()} - > - Insert Below - - - - state().deleteCellSelection.command()} - > - Clear Contents - - Del - - - - - state().deleteTableRow.command()} - > - Delete Row - - - - state().deleteTable.command()} - > - Delete Table - - - - -
-
-
-
- ) -} diff --git a/solid-full/src/components/editor/ui/tag-menu/index.ts b/solid-full/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index d344b33a70..0000000000 --- a/solid-full/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu' diff --git a/solid-full/src/components/editor/ui/tag-menu/tag-menu.tsx b/solid-full/src/components/editor/ui/tag-menu/tag-menu.tsx deleted file mode 100644 index 03e3534da3..0000000000 --- a/solid-full/src/components/editor/ui/tag-menu/tag-menu.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/solid' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/solid/autocomplete' -import { For, type JSX } from 'solid-js' - -const regex = /#[\da-z]*$/i - -export default function TagMenu(props: { - tags: { id: number; label: string }[] -}): JSX.Element { - const editor = useEditor>() - - const handleTagInsert = (id: number, label: string) => { - editor().commands.insertMention({ - id: id.toString(), - value: '#' + label, - kind: 'tag', - }) - editor().commands.insertText({ text: ' ' }) - } - - return ( - - - -
- - No results - - - - {(tag) => ( - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - )} - -
-
-
-
- ) -} diff --git a/solid-full/src/components/editor/ui/toolbar/index.ts b/solid-full/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-full/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-full/src/components/editor/ui/toolbar/toolbar.tsx b/solid-full/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-full/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-full/src/components/editor/ui/user-menu/index.ts b/solid-full/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/solid-full/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/solid-full/src/components/editor/ui/user-menu/user-menu.tsx b/solid-full/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 61d3cd96d8..0000000000 --- a/solid-full/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/solid' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/solid/autocomplete' -import { For, type JSX } from 'solid-js' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}): JSX.Element { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor().commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor().commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - - {(user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - )} - -
-
-
-
- ) -} diff --git a/solid-full/src/index.tsx b/solid-full/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-full/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-full/tsconfig.app.json b/solid-full/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-full/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-full/tsconfig.json b/solid-full/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-full/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-full/tsconfig.node.json b/solid-full/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-full/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-full/vite.config.ts b/solid-full/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-full/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-gap-cursor/.gitignore b/solid-gap-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-gap-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-gap-cursor/README.md b/solid-gap-cursor/README.md deleted file mode 100644 index 6c119ab2a7..0000000000 --- a/solid-gap-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-gap-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-gap-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-gap-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-gap-cursor solid-gap-cursor -cd solid-gap-cursor -npm install -npm run dev -``` diff --git a/solid-gap-cursor/index.html b/solid-gap-cursor/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-gap-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-gap-cursor/package.json b/solid-gap-cursor/package.json deleted file mode 100644 index f1bd270cd7..0000000000 --- a/solid-gap-cursor/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-gap-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-gap-cursor/src/App.tsx b/solid-gap-cursor/src/App.tsx deleted file mode 100644 index ed7e74417e..0000000000 --- a/solid-gap-cursor/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/gap-cursor' - -export default function App() { - return -} diff --git a/solid-gap-cursor/src/app.css b/solid-gap-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-gap-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx b/solid-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx deleted file mode 100644 index 71e17b574a..0000000000 --- a/solid-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-gap-cursor' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/solid-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts deleted file mode 100644 index 599497170d..0000000000 --- a/solid-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineGapCursor(), - defineImage(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/solid-gap-cursor/src/components/editor/examples/gap-cursor/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-gap-cursor/src/components/editor/examples/gap-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/solid-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts deleted file mode 100644 index e40ee2a83b..0000000000 --- a/solid-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - ], -} diff --git a/solid-gap-cursor/src/index.tsx b/solid-gap-cursor/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-gap-cursor/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-gap-cursor/tsconfig.app.json b/solid-gap-cursor/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-gap-cursor/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-gap-cursor/tsconfig.json b/solid-gap-cursor/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-gap-cursor/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-gap-cursor/tsconfig.node.json b/solid-gap-cursor/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-gap-cursor/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-gap-cursor/vite.config.ts b/solid-gap-cursor/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-gap-cursor/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-hard-break/.gitignore b/solid-hard-break/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-hard-break/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-hard-break/README.md b/solid-hard-break/README.md deleted file mode 100644 index c9ebb60380..0000000000 --- a/solid-hard-break/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-hard-break - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-hard-break) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-hard-break) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-hard-break solid-hard-break -cd solid-hard-break -npm install -npm run dev -``` diff --git a/solid-hard-break/index.html b/solid-hard-break/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-hard-break/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-hard-break/package.json b/solid-hard-break/package.json deleted file mode 100644 index 69c0a26a46..0000000000 --- a/solid-hard-break/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-hard-break", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-hard-break/src/App.tsx b/solid-hard-break/src/App.tsx deleted file mode 100644 index db3ea90c2a..0000000000 --- a/solid-hard-break/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/hard-break' - -export default function App() { - return -} diff --git a/solid-hard-break/src/app.css b/solid-hard-break/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-hard-break/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-hard-break/src/components/editor/examples/hard-break/editor.tsx b/solid-hard-break/src/components/editor/examples/hard-break/editor.tsx deleted file mode 100644 index 26023e10f6..0000000000 --- a/solid-hard-break/src/components/editor/examples/hard-break/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-hard-break' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-hard-break/src/components/editor/examples/hard-break/extension.ts b/solid-hard-break/src/components/editor/examples/hard-break/extension.ts deleted file mode 100644 index cad2881056..0000000000 --- a/solid-hard-break/src/components/editor/examples/hard-break/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHardBreak } from 'prosekit/extensions/hard-break' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHardBreak(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-hard-break/src/components/editor/examples/hard-break/index.ts b/solid-hard-break/src/components/editor/examples/hard-break/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-hard-break/src/components/editor/examples/hard-break/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-hard-break/src/components/editor/examples/hard-break/toolbar.tsx b/solid-hard-break/src/components/editor/examples/hard-break/toolbar.tsx deleted file mode 100644 index f6b8cd5d44..0000000000 --- a/solid-hard-break/src/components/editor/examples/hard-break/toolbar.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - hardBreak: { - canExec: editor.commands.insertHardBreak.canExec(), - command: () => editor.commands.insertHardBreak(), - }, - } -} - -export default function Toolbar(): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/solid-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/solid-hard-break/src/components/editor/sample/sample-doc-hard-break.ts deleted file mode 100644 index e1c9786b72..0000000000 --- a/solid-hard-break/src/components/editor/sample/sample-doc-hard-break.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: "O'er all the hilltops", - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Is quiet now,', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'In all the treetops', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hearest thou', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hardly a breath;', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'The birds are asleep in the trees:', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Wait, soon like these', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Thou too shalt rest.', - }, - { - type: 'hardBreak', - }, - ], - }, - ], -} diff --git a/solid-hard-break/src/components/editor/ui/button/button.tsx b/solid-hard-break/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-hard-break/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-hard-break/src/components/editor/ui/button/index.ts b/solid-hard-break/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-hard-break/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-hard-break/src/index.tsx b/solid-hard-break/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-hard-break/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-hard-break/tsconfig.app.json b/solid-hard-break/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-hard-break/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-hard-break/tsconfig.json b/solid-hard-break/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-hard-break/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-hard-break/tsconfig.node.json b/solid-hard-break/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-hard-break/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-hard-break/vite.config.ts b/solid-hard-break/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-hard-break/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-heading/.gitignore b/solid-heading/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-heading/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-heading/README.md b/solid-heading/README.md deleted file mode 100644 index 782676d80f..0000000000 --- a/solid-heading/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-heading - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-heading) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-heading) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-heading solid-heading -cd solid-heading -npm install -npm run dev -``` diff --git a/solid-heading/index.html b/solid-heading/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-heading/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-heading/package.json b/solid-heading/package.json deleted file mode 100644 index b7e5fb196d..0000000000 --- a/solid-heading/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-heading", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-heading/src/App.tsx b/solid-heading/src/App.tsx deleted file mode 100644 index c70e72d05f..0000000000 --- a/solid-heading/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/heading' - -export default function App() { - return -} diff --git a/solid-heading/src/app.css b/solid-heading/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-heading/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-heading/src/components/editor/examples/heading/editor.tsx b/solid-heading/src/components/editor/examples/heading/editor.tsx deleted file mode 100644 index dadd87e073..0000000000 --- a/solid-heading/src/components/editor/examples/heading/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-heading' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-heading/src/components/editor/examples/heading/extension.ts b/solid-heading/src/components/editor/examples/heading/extension.ts deleted file mode 100644 index e4f8e6ace0..0000000000 --- a/solid-heading/src/components/editor/examples/heading/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHeading(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-heading/src/components/editor/examples/heading/index.ts b/solid-heading/src/components/editor/examples/heading/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-heading/src/components/editor/examples/heading/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-heading/src/components/editor/sample/sample-doc-heading.ts b/solid-heading/src/components/editor/sample/sample-doc-heading.ts deleted file mode 100644 index 210497e633..0000000000 --- a/solid-heading/src/components/editor/sample/sample-doc-heading.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'H1' }], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'H2' }], - }, - { - type: 'heading', - attrs: { level: 3 }, - content: [{ type: 'text', text: 'H3' }], - }, - { type: 'paragraph', content: [] }, - ], -} diff --git a/solid-heading/src/components/editor/ui/button/button.tsx b/solid-heading/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-heading/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-heading/src/components/editor/ui/button/index.ts b/solid-heading/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-heading/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-heading/src/components/editor/ui/image-upload-popover/index.ts b/solid-heading/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-heading/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-heading/src/components/editor/ui/toolbar/index.ts b/solid-heading/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-heading/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-heading/src/components/editor/ui/toolbar/toolbar.tsx b/solid-heading/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-heading/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-heading/src/index.tsx b/solid-heading/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-heading/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-heading/tsconfig.app.json b/solid-heading/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-heading/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-heading/tsconfig.json b/solid-heading/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-heading/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-heading/tsconfig.node.json b/solid-heading/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-heading/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-heading/vite.config.ts b/solid-heading/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-heading/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-highlight/.gitignore b/solid-highlight/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-highlight/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-highlight/README.md b/solid-highlight/README.md deleted file mode 100644 index 50c7d5eb90..0000000000 --- a/solid-highlight/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-highlight - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-highlight) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-highlight) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-highlight solid-highlight -cd solid-highlight -npm install -npm run dev -``` diff --git a/solid-highlight/index.html b/solid-highlight/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-highlight/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-highlight/package.json b/solid-highlight/package.json deleted file mode 100644 index 00521fa729..0000000000 --- a/solid-highlight/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-highlight", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-highlight/src/App.tsx b/solid-highlight/src/App.tsx deleted file mode 100644 index 2509b001f7..0000000000 --- a/solid-highlight/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/highlight' - -export default function App() { - return -} diff --git a/solid-highlight/src/app.css b/solid-highlight/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-highlight/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-highlight/src/components/editor/examples/highlight/editor.tsx b/solid-highlight/src/components/editor/examples/highlight/editor.tsx deleted file mode 100644 index 3e0286fd2d..0000000000 --- a/solid-highlight/src/components/editor/examples/highlight/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-highlight' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-highlight/src/components/editor/examples/highlight/extension.ts b/solid-highlight/src/components/editor/examples/highlight/extension.ts deleted file mode 100644 index abc131c3be..0000000000 --- a/solid-highlight/src/components/editor/examples/highlight/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHighlight } from 'prosekit/extensions/highlight' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHighlight(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-highlight/src/components/editor/examples/highlight/index.ts b/solid-highlight/src/components/editor/examples/highlight/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-highlight/src/components/editor/examples/highlight/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-highlight/src/components/editor/examples/highlight/toolbar.tsx b/solid-highlight/src/components/editor/examples/highlight/toolbar.tsx deleted file mode 100644 index 51f99b085e..0000000000 --- a/solid-highlight/src/components/editor/examples/highlight/toolbar.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - highlight: { - isActive: editor.marks.highlight.isActive(), - canExec: editor.commands.toggleHighlight.canExec(), - command: () => editor.commands.toggleHighlight(), - }, - } -} - -export default function Toolbar(): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/solid-highlight/src/components/editor/sample/sample-doc-highlight.ts b/solid-highlight/src/components/editor/sample/sample-doc-highlight.ts deleted file mode 100644 index 0de1a1f7b2..0000000000 --- a/solid-highlight/src/components/editor/sample/sample-doc-highlight.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'highlight', - }, - ], - text: 'This is highlighted text', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/solid-highlight/src/components/editor/ui/button/button.tsx b/solid-highlight/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-highlight/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-highlight/src/components/editor/ui/button/index.ts b/solid-highlight/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-highlight/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-highlight/src/index.tsx b/solid-highlight/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-highlight/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-highlight/tsconfig.app.json b/solid-highlight/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-highlight/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-highlight/tsconfig.json b/solid-highlight/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-highlight/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-highlight/tsconfig.node.json b/solid-highlight/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-highlight/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-highlight/vite.config.ts b/solid-highlight/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-highlight/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-horizontal-rule/.gitignore b/solid-horizontal-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-horizontal-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-horizontal-rule/README.md b/solid-horizontal-rule/README.md deleted file mode 100644 index 55d142f837..0000000000 --- a/solid-horizontal-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-horizontal-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-horizontal-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-horizontal-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-horizontal-rule solid-horizontal-rule -cd solid-horizontal-rule -npm install -npm run dev -``` diff --git a/solid-horizontal-rule/index.html b/solid-horizontal-rule/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-horizontal-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-horizontal-rule/package.json b/solid-horizontal-rule/package.json deleted file mode 100644 index 50de4ddba7..0000000000 --- a/solid-horizontal-rule/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-horizontal-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-horizontal-rule/src/App.tsx b/solid-horizontal-rule/src/App.tsx deleted file mode 100644 index 974e387364..0000000000 --- a/solid-horizontal-rule/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/horizontal-rule' - -export default function App() { - return -} diff --git a/solid-horizontal-rule/src/app.css b/solid-horizontal-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-horizontal-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx deleted file mode 100644 index 05c47ad54e..0000000000 --- a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts deleted file mode 100644 index 49b6121eeb..0000000000 --- a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHorizontalRule(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-horizontal-rule/src/components/editor/ui/button/button.tsx b/solid-horizontal-rule/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-horizontal-rule/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-horizontal-rule/src/components/editor/ui/button/index.ts b/solid-horizontal-rule/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-horizontal-rule/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/solid-horizontal-rule/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-horizontal-rule/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx b/solid-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-horizontal-rule/src/index.tsx b/solid-horizontal-rule/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-horizontal-rule/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-horizontal-rule/tsconfig.app.json b/solid-horizontal-rule/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-horizontal-rule/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-horizontal-rule/tsconfig.json b/solid-horizontal-rule/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-horizontal-rule/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-horizontal-rule/tsconfig.node.json b/solid-horizontal-rule/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-horizontal-rule/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-horizontal-rule/vite.config.ts b/solid-horizontal-rule/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-horizontal-rule/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-image-view/.gitignore b/solid-image-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-image-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-image-view/README.md b/solid-image-view/README.md deleted file mode 100644 index 23192c5114..0000000000 --- a/solid-image-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-image-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-image-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-image-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-image-view solid-image-view -cd solid-image-view -npm install -npm run dev -``` diff --git a/solid-image-view/index.html b/solid-image-view/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-image-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-image-view/package.json b/solid-image-view/package.json deleted file mode 100644 index cb49e68435..0000000000 --- a/solid-image-view/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-image-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-image-view/src/App.tsx b/solid-image-view/src/App.tsx deleted file mode 100644 index 46ede58891..0000000000 --- a/solid-image-view/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/image-view' - -export default function App() { - return -} diff --git a/solid-image-view/src/app.css b/solid-image-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-image-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-image-view/src/components/editor/examples/image-view/editor.tsx b/solid-image-view/src/components/editor/examples/image-view/editor.tsx deleted file mode 100644 index e663c70392..0000000000 --- a/solid-image-view/src/components/editor/examples/image-view/editor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-image' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-image-view/src/components/editor/examples/image-view/extension.ts b/solid-image-view/src/components/editor/examples/image-view/extension.ts deleted file mode 100644 index a21febf634..0000000000 --- a/solid-image-view/src/components/editor/examples/image-view/extension.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineImageUploadHandler } from 'prosekit/extensions/image' - -import { sampleUploader } from '../../sample/sample-uploader' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-image-view/src/components/editor/examples/image-view/index.ts b/solid-image-view/src/components/editor/examples/image-view/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-image-view/src/components/editor/examples/image-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-image-view/src/components/editor/sample/sample-doc-image.ts b/solid-image-view/src/components/editor/sample/sample-doc-image.ts deleted file mode 100644 index c97628339d..0000000000 --- a/solid-image-view/src/components/editor/sample/sample-doc-image.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Paste or drop an image to upload it.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/white/200x200/1', - width: 160, - height: 160, - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/640x360/42', - width: 240, - height: 135, - }, - }, - ], -} diff --git a/solid-image-view/src/components/editor/sample/sample-uploader.ts b/solid-image-view/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/solid-image-view/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/solid-image-view/src/components/editor/ui/image-view/image-view.tsx b/solid-image-view/src/components/editor/ui/image-view/image-view.tsx deleted file mode 100644 index 813fbec79c..0000000000 --- a/solid-image-view/src/components/editor/ui/image-view/image-view.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { UploadTask } from 'prosekit/extensions/file' -import type { ImageAttrs } from 'prosekit/extensions/image' -import type { SolidNodeViewProps } from 'prosekit/solid' -import { ResizableHandle, ResizableRoot } from 'prosekit/solid/resizable' -import { createEffect, createSignal, onCleanup, Show, type JSX } from 'solid-js' - -export default function ImageView(props: SolidNodeViewProps): JSX.Element { - const attrs = () => props.node.attrs as ImageAttrs - const url = () => attrs().src || '' - const uploading = () => url().startsWith('blob:') - - const [aspectRatio, setAspectRatio] = createSignal() - const [error, setError] = createSignal() - const [progress, setProgress] = createSignal(0) - - createEffect(() => { - if (!uploading()) return - - const uploadTask = UploadTask.get(url()) - if (!uploadTask) return - - let canceled = false - - uploadTask.finished.catch((err) => { - if (canceled) return - setError(String(err)) - }) - const unsubscribeProgress = uploadTask.subscribeProgress( - ({ loaded, total }) => { - if (canceled) return - setProgress(total ? loaded / total : 0) - }, - ) - - onCleanup(() => { - canceled = true - unsubscribeProgress() - }) - }) - - const handleImageLoad = (event: Event) => { - const img = event.target as HTMLImageElement - const { naturalWidth, naturalHeight } = img - const ratio = naturalWidth / naturalHeight - if (ratio && Number.isFinite(ratio)) { - setAspectRatio(ratio) - } - if (naturalWidth && naturalHeight && (!attrs().width || !attrs().height)) { - props.setAttrs({ width: naturalWidth, height: naturalHeight }) - } - } - - return ( - props.setAttrs(event.detail)} - attr:data-selected={props.selected ? '' : undefined} - class="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid" - > - - upload preview - - -
-
-
{Math.round(progress() * 100)}%
-
-
- -
-
- -
-
- -
-
-
- ) -} diff --git a/solid-image-view/src/components/editor/ui/image-view/index.ts b/solid-image-view/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index 223c959559..0000000000 --- a/solid-image-view/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - defineSolidNodeView, - type SolidNodeViewComponent, -} from 'prosekit/solid' - -import ImageView from './image-view' - -export function defineImageView(): Extension { - return defineSolidNodeView({ - name: 'image', - component: ImageView satisfies SolidNodeViewComponent, - }) -} diff --git a/solid-image-view/src/index.tsx b/solid-image-view/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-image-view/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-image-view/tsconfig.app.json b/solid-image-view/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-image-view/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-image-view/tsconfig.json b/solid-image-view/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-image-view/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-image-view/tsconfig.node.json b/solid-image-view/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-image-view/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-image-view/vite.config.ts b/solid-image-view/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-image-view/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-inline-menu/.gitignore b/solid-inline-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-inline-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-inline-menu/README.md b/solid-inline-menu/README.md deleted file mode 100644 index ba8971772b..0000000000 --- a/solid-inline-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-inline-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-inline-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-inline-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-inline-menu solid-inline-menu -cd solid-inline-menu -npm install -npm run dev -``` diff --git a/solid-inline-menu/index.html b/solid-inline-menu/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-inline-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-inline-menu/package.json b/solid-inline-menu/package.json deleted file mode 100644 index d4435d25a3..0000000000 --- a/solid-inline-menu/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-inline-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-inline-menu/src/App.tsx b/solid-inline-menu/src/App.tsx deleted file mode 100644 index 660285db3c..0000000000 --- a/solid-inline-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/inline-menu' - -export default function App() { - return -} diff --git a/solid-inline-menu/src/app.css b/solid-inline-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-inline-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-inline-menu/src/components/editor/examples/inline-menu/editor.tsx b/solid-inline-menu/src/components/editor/examples/inline-menu/editor.tsx deleted file mode 100644 index 0ae17e6234..0000000000 --- a/solid-inline-menu/src/components/editor/examples/inline-menu/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-inline-menu' -import { InlineMenu } from '../../ui/inline-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/solid-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/solid-inline-menu/src/components/editor/examples/inline-menu/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/solid-inline-menu/src/components/editor/examples/inline-menu/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/solid-inline-menu/src/components/editor/examples/inline-menu/index.ts b/solid-inline-menu/src/components/editor/examples/inline-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-inline-menu/src/components/editor/examples/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/solid-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts deleted file mode 100644 index 62a5984cb0..0000000000 --- a/solid-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const loremText = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'Try to select some text', - }, - ], - }, - ...Array.from({ length: 10 }, () => ({ - type: 'paragraph' as const, - content: [ - { - type: 'text' as const, - text: loremText, - }, - ], - })), - ], -} diff --git a/solid-inline-menu/src/components/editor/ui/button/button.tsx b/solid-inline-menu/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-inline-menu/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-inline-menu/src/components/editor/ui/button/index.ts b/solid-inline-menu/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-inline-menu/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-inline-menu/src/components/editor/ui/inline-menu/index.ts b/solid-inline-menu/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/solid-inline-menu/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/solid-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index d61df6d794..0000000000 --- a/solid-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/solid' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/solid/inline-popover' -import { createSignal, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu(): JSX.Element { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor().commands.addLink({ href }) - } else { - editor().commands.removeLink() - } - - setLinkMenuOpen(false) - editor().focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - - - - {(item) => ( - setLinkMenuOpen(event.detail)} - > - - - -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
-
- - - -
-
-
- )} -
- - ) -} diff --git a/solid-inline-menu/src/index.tsx b/solid-inline-menu/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-inline-menu/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-inline-menu/tsconfig.app.json b/solid-inline-menu/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-inline-menu/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-inline-menu/tsconfig.json b/solid-inline-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-inline-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-inline-menu/tsconfig.node.json b/solid-inline-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-inline-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-inline-menu/vite.config.ts b/solid-inline-menu/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-inline-menu/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-italic/.gitignore b/solid-italic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-italic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-italic/README.md b/solid-italic/README.md deleted file mode 100644 index af60a0a836..0000000000 --- a/solid-italic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-italic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-italic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-italic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-italic solid-italic -cd solid-italic -npm install -npm run dev -``` diff --git a/solid-italic/index.html b/solid-italic/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-italic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-italic/package.json b/solid-italic/package.json deleted file mode 100644 index 56c9635125..0000000000 --- a/solid-italic/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-italic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-italic/src/App.tsx b/solid-italic/src/App.tsx deleted file mode 100644 index 7ce968b449..0000000000 --- a/solid-italic/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/italic' - -export default function App() { - return -} diff --git a/solid-italic/src/app.css b/solid-italic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-italic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-italic/src/components/editor/examples/italic/editor.tsx b/solid-italic/src/components/editor/examples/italic/editor.tsx deleted file mode 100644 index db8458677d..0000000000 --- a/solid-italic/src/components/editor/examples/italic/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-italic' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-italic/src/components/editor/examples/italic/extension.ts b/solid-italic/src/components/editor/examples/italic/extension.ts deleted file mode 100644 index a456b06aad..0000000000 --- a/solid-italic/src/components/editor/examples/italic/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineItalic(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-italic/src/components/editor/examples/italic/index.ts b/solid-italic/src/components/editor/examples/italic/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-italic/src/components/editor/examples/italic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-italic/src/components/editor/sample/sample-doc-italic.ts b/solid-italic/src/components/editor/sample/sample-doc-italic.ts deleted file mode 100644 index fb99415b2c..0000000000 --- a/solid-italic/src/components/editor/sample/sample-doc-italic.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/solid-italic/src/components/editor/ui/button/button.tsx b/solid-italic/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-italic/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-italic/src/components/editor/ui/button/index.ts b/solid-italic/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-italic/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-italic/src/components/editor/ui/image-upload-popover/index.ts b/solid-italic/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-italic/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-italic/src/components/editor/ui/toolbar/index.ts b/solid-italic/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-italic/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-italic/src/components/editor/ui/toolbar/toolbar.tsx b/solid-italic/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-italic/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-italic/src/index.tsx b/solid-italic/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-italic/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-italic/tsconfig.app.json b/solid-italic/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-italic/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-italic/tsconfig.json b/solid-italic/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-italic/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-italic/tsconfig.node.json b/solid-italic/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-italic/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-italic/vite.config.ts b/solid-italic/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-italic/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-katex/.gitignore b/solid-katex/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-katex/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-katex/README.md b/solid-katex/README.md deleted file mode 100644 index b256116f5a..0000000000 --- a/solid-katex/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-katex - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-katex) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-katex) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-katex solid-katex -cd solid-katex -npm install -npm run dev -``` diff --git a/solid-katex/index.html b/solid-katex/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-katex/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-katex/package.json b/solid-katex/package.json deleted file mode 100644 index 9c94ee55b1..0000000000 --- a/solid-katex/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-solid-katex", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.47", - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-katex/src/App.tsx b/solid-katex/src/App.tsx deleted file mode 100644 index 2a28c7c7d7..0000000000 --- a/solid-katex/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/katex' - -export default function App() { - return -} diff --git a/solid-katex/src/app.css b/solid-katex/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-katex/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-katex/src/components/editor/examples/katex/editor.tsx b/solid-katex/src/components/editor/examples/katex/editor.tsx deleted file mode 100644 index 11c41d38d9..0000000000 --- a/solid-katex/src/components/editor/examples/katex/editor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-tex' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-katex/src/components/editor/examples/katex/extension.ts b/solid-katex/src/components/editor/examples/katex/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/solid-katex/src/components/editor/examples/katex/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-katex/src/components/editor/examples/katex/index.ts b/solid-katex/src/components/editor/examples/katex/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-katex/src/components/editor/examples/katex/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-katex/src/components/editor/sample/katex.ts b/solid-katex/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/solid-katex/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/solid-katex/src/components/editor/sample/sample-doc-tex.ts b/solid-katex/src/components/editor/sample/sample-doc-tex.ts deleted file mode 100644 index 21ccf3e94e..0000000000 --- a/solid-katex/src/components/editor/sample/sample-doc-tex.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Inline equations' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Block equations' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: 'The Gaussian integral:' }], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - ], -} diff --git a/solid-katex/src/index.tsx b/solid-katex/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-katex/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-katex/tsconfig.app.json b/solid-katex/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-katex/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-katex/tsconfig.json b/solid-katex/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-katex/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-katex/tsconfig.node.json b/solid-katex/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-katex/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-katex/vite.config.ts b/solid-katex/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-katex/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-keymap/.gitignore b/solid-keymap/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-keymap/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-keymap/README.md b/solid-keymap/README.md deleted file mode 100644 index 3a877afd76..0000000000 --- a/solid-keymap/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-keymap - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-keymap) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-keymap) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-keymap solid-keymap -cd solid-keymap -npm install -npm run dev -``` diff --git a/solid-keymap/index.html b/solid-keymap/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-keymap/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-keymap/package.json b/solid-keymap/package.json deleted file mode 100644 index 061422dd15..0000000000 --- a/solid-keymap/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-keymap", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-keymap/src/App.tsx b/solid-keymap/src/App.tsx deleted file mode 100644 index da3b6ebb09..0000000000 --- a/solid-keymap/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/keymap' - -export default function App() { - return -} diff --git a/solid-keymap/src/app.css b/solid-keymap/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-keymap/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-keymap/src/components/editor/examples/keymap/editor.tsx b/solid-keymap/src/components/editor/examples/keymap/editor.tsx deleted file mode 100644 index ba3040419a..0000000000 --- a/solid-keymap/src/components/editor/examples/keymap/editor.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import { createSignal, For, Show, type JSX } from 'solid-js' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - const [submissions, setSubmissions] = createSignal([]) - - const pushSubmission = (hotkey: string) => { - const docString = JSON.stringify(editor.getDocJSON()) - const submission = `${new Date().toISOString()} ${hotkey} -${docString}` - setSubmissions((prev) => [...prev, submission]) - } - - return ( - -
- -
-
-
-
-
- Submit Records -
    - - {(submission) => ( -
  1. -
    {submission}
    -
  2. - )} -
    -
- -
No submissions yet
-
-
-
- ) -} diff --git a/solid-keymap/src/components/editor/examples/keymap/extension.ts b/solid-keymap/src/components/editor/examples/keymap/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/solid-keymap/src/components/editor/examples/keymap/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/solid-keymap/src/components/editor/examples/keymap/index.ts b/solid-keymap/src/components/editor/examples/keymap/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-keymap/src/components/editor/examples/keymap/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-keymap/src/components/editor/examples/keymap/toolbar.tsx b/solid-keymap/src/components/editor/examples/keymap/toolbar.tsx deleted file mode 100644 index 81d1152976..0000000000 --- a/solid-keymap/src/components/editor/examples/keymap/toolbar.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { createSignal, type JSX } from 'solid-js' - -import { Button } from '../../ui/button' - -import { useSubmitKeymap } from './use-submit-keymap' - -export default function Toolbar(props: { - onSubmit: (hotkey: string) => void -}): JSX.Element { - const [hotkey, setHotkey] = createSignal<'Shift-Enter' | 'Enter'>( - 'Shift-Enter', - ) - useSubmitKeymap(hotkey, props.onSubmit) - - return ( -
- - - -
- ) -} diff --git a/solid-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts b/solid-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts deleted file mode 100644 index 941fc50744..0000000000 --- a/solid-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Keymap } from 'prosekit/core' -import { useKeymap } from 'prosekit/solid' -import type { Accessor } from 'solid-js' - -export function useSubmitKeymap( - hotkey: Accessor<'Shift-Enter' | 'Enter'>, - onSubmit: (hotkey: string) => void, -): void { - const keymap = () => { - const currentHotkey = hotkey() - return { - [currentHotkey]: () => { - onSubmit(currentHotkey) - return true - }, - } satisfies Keymap - } - - useKeymap(keymap) -} diff --git a/solid-keymap/src/components/editor/ui/button/button.tsx b/solid-keymap/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-keymap/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-keymap/src/components/editor/ui/button/index.ts b/solid-keymap/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-keymap/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-keymap/src/index.tsx b/solid-keymap/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-keymap/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-keymap/tsconfig.app.json b/solid-keymap/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-keymap/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-keymap/tsconfig.json b/solid-keymap/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-keymap/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-keymap/tsconfig.node.json b/solid-keymap/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-keymap/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-keymap/vite.config.ts b/solid-keymap/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-keymap/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-link-mark-view/.gitignore b/solid-link-mark-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-link-mark-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-link-mark-view/README.md b/solid-link-mark-view/README.md deleted file mode 100644 index 29752ace96..0000000000 --- a/solid-link-mark-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-link-mark-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-link-mark-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-link-mark-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-link-mark-view solid-link-mark-view -cd solid-link-mark-view -npm install -npm run dev -``` diff --git a/solid-link-mark-view/index.html b/solid-link-mark-view/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-link-mark-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-link-mark-view/package.json b/solid-link-mark-view/package.json deleted file mode 100644 index f195c0b5e2..0000000000 --- a/solid-link-mark-view/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-link-mark-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-link-mark-view/src/App.tsx b/solid-link-mark-view/src/App.tsx deleted file mode 100644 index 8a8685678d..0000000000 --- a/solid-link-mark-view/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/link-mark-view' - -export default function App() { - return -} diff --git a/solid-link-mark-view/src/app.css b/solid-link-mark-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-link-mark-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx b/solid-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx deleted file mode 100644 index d4bd398bbd..0000000000 --- a/solid-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-link-mark-view' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/solid-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts deleted file mode 100644 index 019835bd63..0000000000 --- a/solid-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineSolidMarkView } from 'prosekit/solid' - -import LinkView from './link-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineSolidMarkView({ - name: 'link', - component: LinkView, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/solid-link-mark-view/src/components/editor/examples/link-mark-view/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-link-mark-view/src/components/editor/examples/link-mark-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx b/solid-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx deleted file mode 100644 index fc3351544d..0000000000 --- a/solid-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import type { SolidMarkViewProps } from 'prosekit/solid' -import { createSignal, onCleanup, onMount, type JSX } from 'solid-js' - -const colors = [ - '#f06292', - '#ba68c8', - '#9575cd', - '#7986cb', - '#64b5f6', - '#4fc3f7', - '#4dd0e1', - '#4db6ac', - '#81c784', - '#aed581', - '#ffb74d', - '#ffa726', - '#ff8a65', - '#d4e157', - '#ffd54f', - '#ffecb3', -] - -function pickRandomColor() { - return colors[Math.floor(Math.random() * colors.length)] -} - -export default function Link(props: SolidMarkViewProps): JSX.Element { - const [color, setColor] = createSignal(colors[0]) - const href = props.mark.attrs.href as string - - onMount(() => { - const interval = setInterval(() => { - setColor(pickRandomColor()) - }, 1000) - - onCleanup(() => clearInterval(interval)) - }) - - return ( - - ) -} diff --git a/solid-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/solid-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts deleted file mode 100644 index 57abd09dd6..0000000000 --- a/solid-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is a link that changes color every second: ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/solid-link-mark-view/src/index.tsx b/solid-link-mark-view/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-link-mark-view/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-link-mark-view/tsconfig.app.json b/solid-link-mark-view/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-link-mark-view/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-link-mark-view/tsconfig.json b/solid-link-mark-view/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-link-mark-view/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-link-mark-view/tsconfig.node.json b/solid-link-mark-view/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-link-mark-view/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-link-mark-view/vite.config.ts b/solid-link-mark-view/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-link-mark-view/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-link/.gitignore b/solid-link/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-link/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-link/README.md b/solid-link/README.md deleted file mode 100644 index 62a1edbb87..0000000000 --- a/solid-link/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-link - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-link) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-link) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-link solid-link -cd solid-link -npm install -npm run dev -``` diff --git a/solid-link/index.html b/solid-link/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-link/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-link/package.json b/solid-link/package.json deleted file mode 100644 index 5401c5c25f..0000000000 --- a/solid-link/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-link", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-link/src/App.tsx b/solid-link/src/App.tsx deleted file mode 100644 index 1cf0f24636..0000000000 --- a/solid-link/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/link' - -export default function App() { - return -} diff --git a/solid-link/src/app.css b/solid-link/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-link/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-link/src/components/editor/examples/link/editor.tsx b/solid-link/src/components/editor/examples/link/editor.tsx deleted file mode 100644 index feddf96214..0000000000 --- a/solid-link/src/components/editor/examples/link/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-link' -import { InlineMenu } from '../../ui/inline-menu' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/solid-link/src/components/editor/examples/link/extension.ts b/solid-link/src/components/editor/examples/link/extension.ts deleted file mode 100644 index bf499147da..0000000000 --- a/solid-link/src/components/editor/examples/link/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLink } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-link/src/components/editor/examples/link/index.ts b/solid-link/src/components/editor/examples/link/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-link/src/components/editor/examples/link/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-link/src/components/editor/sample/sample-doc-link.ts b/solid-link/src/components/editor/sample/sample-doc-link.ts deleted file mode 100644 index 726cf334fd..0000000000 --- a/solid-link/src/components/editor/sample/sample-doc-link.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is an ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/solid-link/src/components/editor/ui/button/button.tsx b/solid-link/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-link/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-link/src/components/editor/ui/button/index.ts b/solid-link/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-link/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-link/src/components/editor/ui/inline-menu/index.ts b/solid-link/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/solid-link/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/solid-link/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-link/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index d61df6d794..0000000000 --- a/solid-link/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/solid' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/solid/inline-popover' -import { createSignal, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu(): JSX.Element { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor().commands.addLink({ href }) - } else { - editor().commands.removeLink() - } - - setLinkMenuOpen(false) - editor().focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - - - - {(item) => ( - setLinkMenuOpen(event.detail)} - > - - - -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
-
- - - -
-
-
- )} -
- - ) -} diff --git a/solid-link/src/index.tsx b/solid-link/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-link/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-link/tsconfig.app.json b/solid-link/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-link/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-link/tsconfig.json b/solid-link/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-link/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-link/tsconfig.node.json b/solid-link/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-link/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-link/vite.config.ts b/solid-link/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-link/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-list-custom-checkbox/.gitignore b/solid-list-custom-checkbox/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-list-custom-checkbox/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-list-custom-checkbox/README.md b/solid-list-custom-checkbox/README.md deleted file mode 100644 index 919d9a0c4b..0000000000 --- a/solid-list-custom-checkbox/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-list-custom-checkbox - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-list-custom-checkbox) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-list-custom-checkbox) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-list-custom-checkbox solid-list-custom-checkbox -cd solid-list-custom-checkbox -npm install -npm run dev -``` diff --git a/solid-list-custom-checkbox/index.html b/solid-list-custom-checkbox/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-list-custom-checkbox/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-list-custom-checkbox/package.json b/solid-list-custom-checkbox/package.json deleted file mode 100644 index ef6bdd17fa..0000000000 --- a/solid-list-custom-checkbox/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-list-custom-checkbox", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-list-custom-checkbox/src/App.tsx b/solid-list-custom-checkbox/src/App.tsx deleted file mode 100644 index 96b82e9a84..0000000000 --- a/solid-list-custom-checkbox/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/list-custom-checkbox' - -export default function App() { - return -} diff --git a/solid-list-custom-checkbox/src/app.css b/solid-list-custom-checkbox/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-list-custom-checkbox/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css deleted file mode 100644 index ec631b72ad..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css +++ /dev/null @@ -1,75 +0,0 @@ -div[data-custom-list-css-enabled] - .ProseMirror - .prosemirror-flat-list[data-list-kind='task'] { - & > .list-marker label { - box-sizing: border-box; - display: flex; - position: relative; - left: calc(var(--spacing) * -0.5); - align-items: center; - cursor: pointer; - transition: transform 0.15s ease-in-out; - - &:hover { - transform: scale(1.1); - } - - &::after { - position: absolute; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - content: ''; - color: var(--color-white); - opacity: 0; - } - - /* https://api.iconify.design/lucide.css?icons=check */ - &::after { - display: inline-block; - background-color: currentColor; - -webkit-mask-image: var(--svg); - mask-image: var(--svg); - -webkit-mask-repeat: no-repeat; - mask-repeat: no-repeat; - -webkit-mask-size: 100% 100%; - mask-size: 100% 100%; - --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); - } - - & input { - box-sizing: border-box; - appearance: none; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - margin: 0; - border-width: 1px; - border-style: solid; - border-radius: var(--radius-md); - border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); - box-shadow: var(--shadow-sm); - cursor: pointer; - transition: all 0.15s ease-in-out; - - &:hover { - box-shadow: var(--shadow-md); - } - - &:checked { - border-color: var(--color-red-500); - background-color: var(--color-red-500); - } - } - } - - &[data-list-checked] > .list-marker label { - &::after { - opacity: 1; - } - } - - &[data-list-checked] { - color: var(--color-gray-400); - text-decoration: line-through; - text-decoration-color: var(--color-gray-400); - } -} diff --git a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx deleted file mode 100644 index a82283f280..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import './custom-list.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-list-custom-checkbox' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ - extension, - defaultContent, - }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/solid-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts deleted file mode 100644 index 972611aed1..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', - }, - { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, - { type: 'text', text: ' for the styles.' }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Completed Task' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Incomplete Task' }], - }, - ], - }, - ], -} diff --git a/solid-list-custom-checkbox/src/components/editor/ui/button/button.tsx b/solid-list-custom-checkbox/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-list-custom-checkbox/src/components/editor/ui/button/index.ts b/solid-list-custom-checkbox/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/solid-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx b/solid-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-list-custom-checkbox/src/index.tsx b/solid-list-custom-checkbox/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-list-custom-checkbox/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-list-custom-checkbox/tsconfig.app.json b/solid-list-custom-checkbox/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-list-custom-checkbox/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-list-custom-checkbox/tsconfig.json b/solid-list-custom-checkbox/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-list-custom-checkbox/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-list-custom-checkbox/tsconfig.node.json b/solid-list-custom-checkbox/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-list-custom-checkbox/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-list-custom-checkbox/vite.config.ts b/solid-list-custom-checkbox/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-list-custom-checkbox/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-list/.gitignore b/solid-list/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-list/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-list/README.md b/solid-list/README.md deleted file mode 100644 index 8fcf0f8d9d..0000000000 --- a/solid-list/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-list - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-list) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-list) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-list solid-list -cd solid-list -npm install -npm run dev -``` diff --git a/solid-list/index.html b/solid-list/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-list/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-list/package.json b/solid-list/package.json deleted file mode 100644 index b6f03a420f..0000000000 --- a/solid-list/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-list", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-list/src/App.tsx b/solid-list/src/App.tsx deleted file mode 100644 index 73f050ef0c..0000000000 --- a/solid-list/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/list' - -export default function App() { - return -} diff --git a/solid-list/src/app.css b/solid-list/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-list/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-list/src/components/editor/examples/list/editor.tsx b/solid-list/src/components/editor/examples/list/editor.tsx deleted file mode 100644 index c4874a51be..0000000000 --- a/solid-list/src/components/editor/examples/list/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-list' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-list/src/components/editor/examples/list/extension.ts b/solid-list/src/components/editor/examples/list/extension.ts deleted file mode 100644 index f66bae6ff7..0000000000 --- a/solid-list/src/components/editor/examples/list/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineList } from 'prosekit/extensions/list' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineList(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-list/src/components/editor/examples/list/index.ts b/solid-list/src/components/editor/examples/list/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-list/src/components/editor/examples/list/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-list/src/components/editor/sample/sample-doc-list.ts b/solid-list/src/components/editor/sample/sample-doc-list.ts deleted file mode 100644 index 091bc37185..0000000000 --- a/solid-list/src/components/editor/sample/sample-doc-list.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Ordered List' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'toggle', collapsed: true }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, - { - type: 'list', - attrs: { - kind: 'bullet', - }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, - ], - }, - ], - }, - ], -} diff --git a/solid-list/src/components/editor/ui/button/button.tsx b/solid-list/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-list/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-list/src/components/editor/ui/button/index.ts b/solid-list/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-list/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-list/src/components/editor/ui/image-upload-popover/index.ts b/solid-list/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-list/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-list/src/components/editor/ui/toolbar/index.ts b/solid-list/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-list/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-list/src/components/editor/ui/toolbar/toolbar.tsx b/solid-list/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-list/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-list/src/index.tsx b/solid-list/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-list/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-list/tsconfig.app.json b/solid-list/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-list/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-list/tsconfig.json b/solid-list/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-list/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-list/tsconfig.node.json b/solid-list/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-list/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-list/vite.config.ts b/solid-list/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-list/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-loro/.gitignore b/solid-loro/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-loro/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-loro/README.md b/solid-loro/README.md deleted file mode 100644 index b8f79c0da7..0000000000 --- a/solid-loro/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-loro - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-loro) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-loro) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-loro solid-loro -cd solid-loro -npm install -npm run dev -``` diff --git a/solid-loro/index.html b/solid-loro/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-loro/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-loro/package.json b/solid-loro/package.json deleted file mode 100644 index 32dff9f365..0000000000 --- a/solid-loro/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-solid-loro", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "loro-crdt": "^1.12.1", - "loro-prosemirror": "^0.4.3", - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12", - "vite-plugin-wasm": "^3.6.0" - } -} diff --git a/solid-loro/src/App.tsx b/solid-loro/src/App.tsx deleted file mode 100644 index 71d2a6b080..0000000000 --- a/solid-loro/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/loro' - -export default function App() { - return -} diff --git a/solid-loro/src/app.css b/solid-loro/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-loro/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-loro/src/components/editor/examples/loro/editor-component.tsx b/solid-loro/src/components/editor/examples/loro/editor-component.tsx deleted file mode 100644 index bfcbe67370..0000000000 --- a/solid-loro/src/components/editor/examples/loro/editor-component.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/loro/style.css' - -import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function EditorComponent(props: { - loro: LoroDocType - awareness: CursorAwareness -}): JSX.Element { - const extension = defineExtension(props.loro, props.awareness) - const editor = createEditor({ extension }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-loro/src/components/editor/examples/loro/editor.tsx b/solid-loro/src/components/editor/examples/loro/editor.tsx deleted file mode 100644 index f9f94e3b93..0000000000 --- a/solid-loro/src/components/editor/examples/loro/editor.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { LoroDoc, type AwarenessListener } from 'loro-crdt' -import { CursorAwareness, type LoroDocType } from 'loro-prosemirror' -import { onCleanup, type JSX } from 'solid-js' - -import EditorComponent from './editor-component' - -export default function Editor(): JSX.Element { - const loroA: LoroDocType = new LoroDoc() - const loroB: LoroDocType = new LoroDoc() - - const idA = loroA.peerIdStr - const idB = loroB.peerIdStr - - const awarenessA = new CursorAwareness(idA) - const awarenessB = new CursorAwareness(idB) - - loroA.import(loroB.export({ mode: 'update' })) - loroB.import(loroA.export({ mode: 'update' })) - - const unsubscribeA = loroA.subscribeLocalUpdates((updates) => { - loroB.import(updates) - }) - - const unsubscribeB = loroB.subscribeLocalUpdates((updates) => { - loroA.import(updates) - }) - - const awarenessAListener: AwarenessListener = (_, origin) => { - if (origin === 'local') { - awarenessB.apply(awarenessA.encode([idA])) - } - } - - const awarenessBListener: AwarenessListener = (_, origin) => { - if (origin === 'local') { - awarenessA.apply(awarenessB.encode([idB])) - } - } - - awarenessA.addListener(awarenessAListener) - awarenessB.addListener(awarenessBListener) - - onCleanup(() => { - awarenessA.removeListener(awarenessAListener) - awarenessB.removeListener(awarenessBListener) - unsubscribeA() - unsubscribeB() - }) - - return ( -
- - -
- ) -} diff --git a/solid-loro/src/components/editor/examples/loro/extension.ts b/solid-loro/src/components/editor/examples/loro/extension.ts deleted file mode 100644 index 5b2380c7c9..0000000000 --- a/solid-loro/src/components/editor/examples/loro/extension.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineLoro } from 'prosekit/extensions/loro' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { - return union( - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineLoro({ doc, awareness }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-loro/src/components/editor/examples/loro/index.ts b/solid-loro/src/components/editor/examples/loro/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-loro/src/components/editor/examples/loro/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-loro/src/components/editor/ui/button/button.tsx b/solid-loro/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-loro/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-loro/src/components/editor/ui/button/index.ts b/solid-loro/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-loro/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-loro/src/components/editor/ui/image-upload-popover/index.ts b/solid-loro/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-loro/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-loro/src/components/editor/ui/toolbar/index.ts b/solid-loro/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-loro/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-loro/src/components/editor/ui/toolbar/toolbar.tsx b/solid-loro/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-loro/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-loro/src/index.tsx b/solid-loro/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-loro/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-loro/tsconfig.app.json b/solid-loro/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-loro/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-loro/tsconfig.json b/solid-loro/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-loro/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-loro/tsconfig.node.json b/solid-loro/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-loro/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-loro/vite.config.ts b/solid-loro/vite.config.ts deleted file mode 100644 index 1987ce5dc6..0000000000 --- a/solid-loro/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import wasm from 'vite-plugin-wasm' -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [wasm(), solid(), tailwindcss()], -}) diff --git a/solid-mark-rule/.gitignore b/solid-mark-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-mark-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-mark-rule/README.md b/solid-mark-rule/README.md deleted file mode 100644 index 74c0c98b4c..0000000000 --- a/solid-mark-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-mark-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-mark-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-mark-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-mark-rule solid-mark-rule -cd solid-mark-rule -npm install -npm run dev -``` diff --git a/solid-mark-rule/index.html b/solid-mark-rule/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-mark-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-mark-rule/package.json b/solid-mark-rule/package.json deleted file mode 100644 index 535f0d5adb..0000000000 --- a/solid-mark-rule/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-mark-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-mark-rule/src/App.tsx b/solid-mark-rule/src/App.tsx deleted file mode 100644 index 4e93a4bf60..0000000000 --- a/solid-mark-rule/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/mark-rule' - -export default function App() { - return -} diff --git a/solid-mark-rule/src/app.css b/solid-mark-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-mark-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-mark-rule/src/components/editor/examples/mark-rule/editor.tsx b/solid-mark-rule/src/components/editor/examples/mark-rule/editor.tsx deleted file mode 100644 index 6f695978e8..0000000000 --- a/solid-mark-rule/src/components/editor/examples/mark-rule/editor.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { defineExtension } from './extension' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/solid-mark-rule/src/components/editor/examples/mark-rule/extension.ts deleted file mode 100644 index 4a1de40783..0000000000 --- a/solid-mark-rule/src/components/editor/examples/mark-rule/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - defineBaseCommands, - defineBaseKeymap, - defineHistory, - union, -} from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { definePlaceholder } from 'prosekit/extensions/placeholder' -import { defineText } from 'prosekit/extensions/text' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -import { defineIssueLink } from './issue-link' - -export function defineExtension() { - return union( - defineDoc(), - defineText(), - defineParagraph(), - defineHistory(), - defineBaseKeymap(), - defineBaseCommands(), - defineVirtualSelection(), - defineLinkSpec(), - defineLinkMarkRule(), - definePlaceholder({ placeholder: 'Try typing #123' }), - defineIssueLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-mark-rule/src/components/editor/examples/mark-rule/index.ts b/solid-mark-rule/src/components/editor/examples/mark-rule/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-mark-rule/src/components/editor/examples/mark-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/solid-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts deleted file mode 100644 index 3840b5e53d..0000000000 --- a/solid-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { defineMarkSpec, union } from 'prosekit/core' -import { defineMarkRule } from 'prosekit/extensions/mark-rule' - -export function defineIssueLink() { - return union( - defineMarkSpec({ - name: 'issueLink', - inclusive: false, - attrs: { - issueNumber: {}, - }, - toDOM(node) { - const issueNumber = node.attrs.issueNumber as number - return [ - 'a', - { - href: `https://example.com/issues/${issueNumber}`, - title: `Issue #${issueNumber}`, - }, - 0, - ] - }, - }), - defineMarkRule({ - regex: /#(\d+)/g, - type: 'issueLink', - attrs: (match) => { - return { issueNumber: Number.parseInt(match[1] || '0') } - }, - }), - ) -} diff --git a/solid-mark-rule/src/index.tsx b/solid-mark-rule/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-mark-rule/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-mark-rule/tsconfig.app.json b/solid-mark-rule/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-mark-rule/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-mark-rule/tsconfig.json b/solid-mark-rule/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-mark-rule/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-mark-rule/tsconfig.node.json b/solid-mark-rule/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-mark-rule/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-mark-rule/vite.config.ts b/solid-mark-rule/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-mark-rule/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-minimal/.gitignore b/solid-minimal/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-minimal/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-minimal/README.md b/solid-minimal/README.md deleted file mode 100644 index a4caabd2bb..0000000000 --- a/solid-minimal/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-minimal - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-minimal) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-minimal) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-minimal solid-minimal -cd solid-minimal -npm install -npm run dev -``` diff --git a/solid-minimal/index.html b/solid-minimal/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-minimal/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-minimal/package.json b/solid-minimal/package.json deleted file mode 100644 index 94b62599a7..0000000000 --- a/solid-minimal/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-minimal", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-minimal/src/App.tsx b/solid-minimal/src/App.tsx deleted file mode 100644 index 523aea224a..0000000000 --- a/solid-minimal/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/minimal' - -export default function App() { - return -} diff --git a/solid-minimal/src/app.css b/solid-minimal/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-minimal/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-minimal/src/components/editor/examples/minimal/editor.tsx b/solid-minimal/src/components/editor/examples/minimal/editor.tsx deleted file mode 100644 index eef69dfca1..0000000000 --- a/solid-minimal/src/components/editor/examples/minimal/editor.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -export default function Editor(): JSX.Element { - const extension = defineBasicExtension() - const editor = createEditor({ extension }) - - return ( - -
-
- ) -} diff --git a/solid-minimal/src/components/editor/examples/minimal/index.ts b/solid-minimal/src/components/editor/examples/minimal/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-minimal/src/components/editor/examples/minimal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-minimal/src/index.tsx b/solid-minimal/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-minimal/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-minimal/tsconfig.app.json b/solid-minimal/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-minimal/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-minimal/tsconfig.json b/solid-minimal/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-minimal/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-minimal/tsconfig.node.json b/solid-minimal/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-minimal/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-minimal/vite.config.ts b/solid-minimal/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-minimal/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-placeholder/.gitignore b/solid-placeholder/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-placeholder/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-placeholder/README.md b/solid-placeholder/README.md deleted file mode 100644 index 2686f67d40..0000000000 --- a/solid-placeholder/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-placeholder - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-placeholder) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-placeholder) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-placeholder solid-placeholder -cd solid-placeholder -npm install -npm run dev -``` diff --git a/solid-placeholder/index.html b/solid-placeholder/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-placeholder/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-placeholder/package.json b/solid-placeholder/package.json deleted file mode 100644 index 575ceb9bad..0000000000 --- a/solid-placeholder/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-placeholder", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-placeholder/src/App.tsx b/solid-placeholder/src/App.tsx deleted file mode 100644 index 919da8503a..0000000000 --- a/solid-placeholder/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/placeholder' - -export default function App() { - return -} diff --git a/solid-placeholder/src/app.css b/solid-placeholder/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-placeholder/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-placeholder/src/components/editor/examples/placeholder/editor.tsx b/solid-placeholder/src/components/editor/examples/placeholder/editor.tsx deleted file mode 100644 index e759ced14a..0000000000 --- a/solid-placeholder/src/components/editor/examples/placeholder/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, jsonFromNode, type NodeJSON } from 'prosekit/core' -import type { ProseMirrorNode } from 'prosekit/pm/model' -import { ProseKit, useDocChange } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { defineExtension } from './extension' - -export default function Editor(props: { - initialContent?: NodeJSON - onDocUpdate?: (doc: NodeJSON) => void -}): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ - extension, - defaultContent: props.initialContent, - }) - - const handleDocChange = (doc: ProseMirrorNode) => - props.onDocUpdate?.(jsonFromNode(doc)) - useDocChange(handleDocChange, { editor }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-placeholder/src/components/editor/examples/placeholder/extension.ts b/solid-placeholder/src/components/editor/examples/placeholder/extension.ts deleted file mode 100644 index 12d0ba26f4..0000000000 --- a/solid-placeholder/src/components/editor/examples/placeholder/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Type something...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-placeholder/src/components/editor/examples/placeholder/index.ts b/solid-placeholder/src/components/editor/examples/placeholder/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-placeholder/src/components/editor/examples/placeholder/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-placeholder/src/index.tsx b/solid-placeholder/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-placeholder/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-placeholder/tsconfig.app.json b/solid-placeholder/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-placeholder/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-placeholder/tsconfig.json b/solid-placeholder/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-placeholder/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-placeholder/tsconfig.node.json b/solid-placeholder/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-placeholder/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-placeholder/vite.config.ts b/solid-placeholder/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-placeholder/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-readonly/.gitignore b/solid-readonly/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-readonly/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-readonly/README.md b/solid-readonly/README.md deleted file mode 100644 index 1dadf55d5d..0000000000 --- a/solid-readonly/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-readonly - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-readonly) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-readonly) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-readonly solid-readonly -cd solid-readonly -npm install -npm run dev -``` diff --git a/solid-readonly/index.html b/solid-readonly/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-readonly/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-readonly/package.json b/solid-readonly/package.json deleted file mode 100644 index f031483b7c..0000000000 --- a/solid-readonly/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-readonly", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-readonly/src/App.tsx b/solid-readonly/src/App.tsx deleted file mode 100644 index dc728e840f..0000000000 --- a/solid-readonly/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/readonly' - -export default function App() { - return -} diff --git a/solid-readonly/src/app.css b/solid-readonly/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-readonly/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-readonly/src/components/editor/examples/readonly/editor.tsx b/solid-readonly/src/components/editor/examples/readonly/editor.tsx deleted file mode 100644 index 0752dfca2d..0000000000 --- a/solid-readonly/src/components/editor/examples/readonly/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-readonly' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-readonly/src/components/editor/examples/readonly/extension.ts b/solid-readonly/src/components/editor/examples/readonly/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/solid-readonly/src/components/editor/examples/readonly/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/solid-readonly/src/components/editor/examples/readonly/index.ts b/solid-readonly/src/components/editor/examples/readonly/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-readonly/src/components/editor/examples/readonly/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-readonly/src/components/editor/examples/readonly/toolbar.tsx b/solid-readonly/src/components/editor/examples/readonly/toolbar.tsx deleted file mode 100644 index 0184e5c77f..0000000000 --- a/solid-readonly/src/components/editor/examples/readonly/toolbar.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { JSX } from 'solid-js' - -import { Button } from '../../ui/button' - -import { useReadonly } from './use-readonly' - -export default function Toolbar(): JSX.Element { - const { readonly, setReadonly } = useReadonly() - - return ( -
- - - -
- ) -} diff --git a/solid-readonly/src/components/editor/examples/readonly/use-readonly.ts b/solid-readonly/src/components/editor/examples/readonly/use-readonly.ts deleted file mode 100644 index 3aea61f0bb..0000000000 --- a/solid-readonly/src/components/editor/examples/readonly/use-readonly.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineReadonly } from 'prosekit/extensions/readonly' -import { useExtension } from 'prosekit/solid' -import { createMemo, createSignal } from 'solid-js' - -export function useReadonly() { - const [readonly, setReadonly] = createSignal(true) - - const extension = createMemo(() => { - return readonly() ? defineReadonly() : null - }) - useExtension(extension) - - return { readonly, setReadonly } -} diff --git a/solid-readonly/src/components/editor/sample/sample-doc-readonly.ts b/solid-readonly/src/components/editor/sample/sample-doc-readonly.ts deleted file mode 100644 index abd9e2c6ac..0000000000 --- a/solid-readonly/src/components/editor/sample/sample-doc-readonly.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', - }, - ], - }, - ], -} diff --git a/solid-readonly/src/components/editor/ui/button/button.tsx b/solid-readonly/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-readonly/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-readonly/src/components/editor/ui/button/index.ts b/solid-readonly/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-readonly/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-readonly/src/index.tsx b/solid-readonly/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-readonly/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-readonly/tsconfig.app.json b/solid-readonly/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-readonly/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-readonly/tsconfig.json b/solid-readonly/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-readonly/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-readonly/tsconfig.node.json b/solid-readonly/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-readonly/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-readonly/vite.config.ts b/solid-readonly/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-readonly/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-rtl/.gitignore b/solid-rtl/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-rtl/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-rtl/README.md b/solid-rtl/README.md deleted file mode 100644 index 467a5010fb..0000000000 --- a/solid-rtl/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-rtl - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-rtl) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-rtl) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-rtl solid-rtl -cd solid-rtl -npm install -npm run dev -``` diff --git a/solid-rtl/index.html b/solid-rtl/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-rtl/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-rtl/package.json b/solid-rtl/package.json deleted file mode 100644 index 16eaf1e341..0000000000 --- a/solid-rtl/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-rtl", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-rtl/src/App.tsx b/solid-rtl/src/App.tsx deleted file mode 100644 index b7c8653ece..0000000000 --- a/solid-rtl/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/rtl' - -export default function App() { - return -} diff --git a/solid-rtl/src/app.css b/solid-rtl/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-rtl/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-rtl/src/components/editor/examples/rtl/editor.tsx b/solid-rtl/src/components/editor/examples/rtl/editor.tsx deleted file mode 100644 index 98f5b62503..0000000000 --- a/solid-rtl/src/components/editor/examples/rtl/editor.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-rtl' -import { sampleUploader } from '../../sample/sample-uploader' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' -import { InlineMenu } from '../../ui/inline-menu' -import { SlashMenu } from '../../ui/slash-menu' -import { TableHandle } from '../../ui/table-handle' -import { Toolbar } from '../../ui/toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const extension = defineBasicExtension() - const defaultContent = props.initialContent ?? sampleContent - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
- - - - - -
-
-
- ) -} diff --git a/solid-rtl/src/components/editor/examples/rtl/index.ts b/solid-rtl/src/components/editor/examples/rtl/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-rtl/src/components/editor/examples/rtl/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-rtl/src/components/editor/sample/sample-doc-rtl.ts b/solid-rtl/src/components/editor/sample/sample-doc-rtl.ts deleted file mode 100644 index 696e797724..0000000000 --- a/solid-rtl/src/components/editor/sample/sample-doc-rtl.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const translation = { - Paragraph: 'فقرة', - 'Root list item': 'عنصر قائمة جذري', - 'Sub list item': 'عنصر قائمة فرعي', - 'Completed task': 'مهمة مكتملة', - 'Pending task': 'مهمة قيد الانتظار', - Quote: 'اقتباس', -} as const - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Right to Left' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Paragraph'] }], - }, - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Root list item'] }], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Completed task'] }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Pending task'] }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: 'hello world', - }, - ], - }, - - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, - ], - }, - ], - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: translation['Quote'], - }, - ], - }, - ], - }, - ], -} diff --git a/solid-rtl/src/components/editor/sample/sample-uploader.ts b/solid-rtl/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/solid-rtl/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/solid-rtl/src/components/editor/ui/block-handle/block-handle.tsx b/solid-rtl/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 95e1693ef6..0000000000 --- a/solid-rtl/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/solid/block-handle' -import type { JSX } from 'solid-js' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props): JSX.Element { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/solid-rtl/src/components/editor/ui/block-handle/index.ts b/solid-rtl/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/solid-rtl/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/solid-rtl/src/components/editor/ui/button/button.tsx b/solid-rtl/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-rtl/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-rtl/src/components/editor/ui/button/index.ts b/solid-rtl/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-rtl/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/solid-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx deleted file mode 100644 index c5a24c7faa..0000000000 --- a/solid-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { DropIndicator as BaseDropIndicator } from 'prosekit/solid/drop-indicator' -import type { JSX } from 'solid-js' - -export default function DropIndicator(): JSX.Element { - return -} diff --git a/solid-rtl/src/components/editor/ui/drop-indicator/index.ts b/solid-rtl/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index f8fb7139c4..0000000000 --- a/solid-rtl/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator' diff --git a/solid-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-rtl/src/components/editor/ui/image-upload-popover/index.ts b/solid-rtl/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-rtl/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-rtl/src/components/editor/ui/inline-menu/index.ts b/solid-rtl/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/solid-rtl/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/solid-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index d61df6d794..0000000000 --- a/solid-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/solid' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/solid/inline-popover' -import { createSignal, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu(): JSX.Element { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor().commands.addLink({ href }) - } else { - editor().commands.removeLink() - } - - setLinkMenuOpen(false) - editor().focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - - - - {(item) => ( - setLinkMenuOpen(event.detail)} - > - - - -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
-
- - - -
-
-
- )} -
- - ) -} diff --git a/solid-rtl/src/components/editor/ui/slash-menu/index.ts b/solid-rtl/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/solid-rtl/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index aae5f3dc6b..0000000000 --- a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { AutocompleteEmpty } from 'prosekit/solid/autocomplete' -import type { JSX } from 'solid-js' - -export default function SlashMenuEmpty(): JSX.Element { - return ( - - No results - - ) -} diff --git a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 9d8101d019..0000000000 --- a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { AutocompleteItem } from 'prosekit/solid/autocomplete' -import { Show, type JSX } from 'solid-js' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}): JSX.Element { - return ( - - {props.label} - - - {props.kbd} - - - - ) -} diff --git a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index c7090d7f36..0000000000 --- a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/solid' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/solid/autocomplete' -import type { JSX } from 'solid-js' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor().commands.setParagraph()} - /> - - editor().commands.setHeading({ level: 1 })} - /> - - editor().commands.setHeading({ level: 2 })} - /> - - editor().commands.setHeading({ level: 3 })} - /> - - editor().commands.wrapInList({ kind: 'bullet' })} - /> - - editor().commands.wrapInList({ kind: 'ordered' })} - /> - - editor().commands.wrapInList({ kind: 'task' })} - /> - - editor().commands.wrapInList({ kind: 'toggle' })} - /> - - editor().commands.setBlockquote()} - /> - - editor().commands.insertTable({ row: 3, col: 3 })} - /> - - editor().commands.insertHorizontalRule()} - /> - - editor().commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/solid-rtl/src/components/editor/ui/table-handle/index.ts b/solid-rtl/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/solid-rtl/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/solid-rtl/src/components/editor/ui/table-handle/table-handle.tsx b/solid-rtl/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index 463f4d3657..0000000000 --- a/solid-rtl/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/solid' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/solid/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/solid/table-handle' -import { Show, type JSX } from 'solid-js' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props): JSX.Element { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - - state().addTableColumnBefore.command()} - > - Insert Left - - - - state().addTableColumnAfter.command()} - > - Insert Right - - - - state().deleteCellSelection.command()} - > - Clear Contents - - Del - - - - - state().deleteTableColumn.command()} - > - Delete Column - - - - state().deleteTable.command()} - > - Delete Table - - - - -
-
-
- - - - -
-
- - - - state().addTableRowAbove.command()} - > - Insert Above - - - - state().addTableRowBelow.command()} - > - Insert Below - - - - state().deleteCellSelection.command()} - > - Clear Contents - - Del - - - - - state().deleteTableRow.command()} - > - Delete Row - - - - state().deleteTable.command()} - > - Delete Table - - - - -
-
-
-
- ) -} diff --git a/solid-rtl/src/components/editor/ui/toolbar/index.ts b/solid-rtl/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-rtl/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-rtl/src/components/editor/ui/toolbar/toolbar.tsx b/solid-rtl/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-rtl/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-rtl/src/index.tsx b/solid-rtl/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-rtl/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-rtl/tsconfig.app.json b/solid-rtl/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-rtl/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-rtl/tsconfig.json b/solid-rtl/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-rtl/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-rtl/tsconfig.node.json b/solid-rtl/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-rtl/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-rtl/vite.config.ts b/solid-rtl/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-rtl/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-save-html/.gitignore b/solid-save-html/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-save-html/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-save-html/README.md b/solid-save-html/README.md deleted file mode 100644 index cf82df568e..0000000000 --- a/solid-save-html/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-save-html - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-save-html) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-save-html) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-save-html solid-save-html -cd solid-save-html -npm install -npm run dev -``` diff --git a/solid-save-html/index.html b/solid-save-html/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-save-html/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-save-html/package.json b/solid-save-html/package.json deleted file mode 100644 index b5ac06d34a..0000000000 --- a/solid-save-html/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-save-html", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-save-html/src/App.tsx b/solid-save-html/src/App.tsx deleted file mode 100644 index cd1a678bb6..0000000000 --- a/solid-save-html/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-html' - -export default function App() { - return -} diff --git a/solid-save-html/src/app.css b/solid-save-html/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-save-html/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-save-html/src/components/editor/examples/save-html/editor.tsx b/solid-save-html/src/components/editor/examples/save-html/editor.tsx deleted file mode 100644 index 8a6c1886b1..0000000000 --- a/solid-save-html/src/components/editor/examples/save-html/editor.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, jsonFromHTML } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/solid' -import { createSignal, For, type JSX } from 'solid-js' - -export default function Editor(): JSX.Element { - const [records, setRecords] = createSignal([]) - const [hasUnsavedChange, setHasUnsavedChange] = createSignal(false) - - const extension = defineBasicExtension() - const editor = createEditor({ extension }) - - const handleDocChange = () => setHasUnsavedChange(true) - useDocChange(handleDocChange, { editor }) - - const handleSave = () => { - const record = editor.getDocHTML() - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - } - - const handleLoad = (record: string) => { - editor.setContent(jsonFromHTML(record, { schema: editor.schema })) - setHasUnsavedChange(false) - } - - return ( -
- -
    - - {(record) => ( -
  • - - -
    {record}
    -
    -
  • - )} -
    -
- -
-
-
-
-
- ) -} diff --git a/solid-save-html/src/components/editor/examples/save-html/index.ts b/solid-save-html/src/components/editor/examples/save-html/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-save-html/src/components/editor/examples/save-html/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-save-html/src/index.tsx b/solid-save-html/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-save-html/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-save-html/tsconfig.app.json b/solid-save-html/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-save-html/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-save-html/tsconfig.json b/solid-save-html/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-save-html/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-save-html/tsconfig.node.json b/solid-save-html/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-save-html/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-save-html/vite.config.ts b/solid-save-html/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-save-html/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-save-json/.gitignore b/solid-save-json/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-save-json/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-save-json/README.md b/solid-save-json/README.md deleted file mode 100644 index 335ce26bb9..0000000000 --- a/solid-save-json/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-save-json - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-save-json) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-save-json) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-save-json solid-save-json -cd solid-save-json -npm install -npm run dev -``` diff --git a/solid-save-json/index.html b/solid-save-json/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-save-json/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-save-json/package.json b/solid-save-json/package.json deleted file mode 100644 index e6ccd98d46..0000000000 --- a/solid-save-json/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-save-json", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-save-json/src/App.tsx b/solid-save-json/src/App.tsx deleted file mode 100644 index c35583f0b4..0000000000 --- a/solid-save-json/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-json' - -export default function App() { - return -} diff --git a/solid-save-json/src/app.css b/solid-save-json/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-save-json/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-save-json/src/components/editor/examples/save-json/editor.tsx b/solid-save-json/src/components/editor/examples/save-json/editor.tsx deleted file mode 100644 index 4b31002153..0000000000 --- a/solid-save-json/src/components/editor/examples/save-json/editor.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/solid' -import { createSignal, For, type JSX } from 'solid-js' - -export default function Editor(): JSX.Element { - const [records, setRecords] = createSignal([]) - const [hasUnsavedChange, setHasUnsavedChange] = createSignal(false) - - const extension = defineBasicExtension() - const editor = createEditor({ extension }) - - const handleDocChange = () => setHasUnsavedChange(true) - useDocChange(handleDocChange, { editor }) - - const handleSave = () => { - const record = JSON.stringify(editor.getDocJSON()) - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - } - - const handleLoad = (record: string) => { - editor.setContent(JSON.parse(record) as NodeJSON) - setHasUnsavedChange(false) - } - - return ( -
- -
    - - {(record) => ( -
  • - - -
    {record}
    -
    -
  • - )} -
    -
- -
-
-
-
-
- ) -} diff --git a/solid-save-json/src/components/editor/examples/save-json/index.ts b/solid-save-json/src/components/editor/examples/save-json/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-save-json/src/components/editor/examples/save-json/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-save-json/src/index.tsx b/solid-save-json/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-save-json/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-save-json/tsconfig.app.json b/solid-save-json/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-save-json/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-save-json/tsconfig.json b/solid-save-json/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-save-json/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-save-json/tsconfig.node.json b/solid-save-json/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-save-json/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-save-json/vite.config.ts b/solid-save-json/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-save-json/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-save-markdown/.gitignore b/solid-save-markdown/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-save-markdown/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-save-markdown/README.md b/solid-save-markdown/README.md deleted file mode 100644 index 88666ea568..0000000000 --- a/solid-save-markdown/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-save-markdown - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-save-markdown) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-save-markdown) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-save-markdown solid-save-markdown -cd solid-save-markdown -npm install -npm run dev -``` diff --git a/solid-save-markdown/index.html b/solid-save-markdown/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-save-markdown/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-save-markdown/package.json b/solid-save-markdown/package.json deleted file mode 100644 index 5543b5a1fb..0000000000 --- a/solid-save-markdown/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "example-solid-save-markdown", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "rehype-parse": "^9.0.1", - "rehype-remark": "^10.0.1", - "remark-gfm": "^4.0.1", - "remark-html": "^16.0.1", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "solid-js": "^1.9.13", - "unified": "^11.0.5" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-save-markdown/src/App.tsx b/solid-save-markdown/src/App.tsx deleted file mode 100644 index 776d1fdf5b..0000000000 --- a/solid-save-markdown/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/save-markdown' - -export default function App() { - return -} diff --git a/solid-save-markdown/src/app.css b/solid-save-markdown/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-save-markdown/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-save-markdown/src/components/editor/examples/save-markdown/editor.tsx b/solid-save-markdown/src/components/editor/examples/save-markdown/editor.tsx deleted file mode 100644 index 03452c522f..0000000000 --- a/solid-save-markdown/src/components/editor/examples/save-markdown/editor.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor, jsonFromHTML } from 'prosekit/core' -import { ProseKit, useDocChange } from 'prosekit/solid' -import { createSignal, For, type JSX } from 'solid-js' - -import { htmlFromMarkdown, markdownFromHTML } from './markdown' - -export default function Editor(): JSX.Element { - const [records, setRecords] = createSignal([]) - const [hasUnsavedChange, setHasUnsavedChange] = createSignal(false) - - const extension = defineBasicExtension() - const editor = createEditor({ extension }) - - const handleDocChange = () => setHasUnsavedChange(true) - useDocChange(handleDocChange, { editor }) - - const handleSave = () => { - const html = editor.getDocHTML() - const record = markdownFromHTML(html) - setRecords((prev) => [...prev, record]) - setHasUnsavedChange(false) - } - - const handleLoad = (record: string) => { - const html = htmlFromMarkdown(record) - editor.setContent(jsonFromHTML(html, { schema: editor.schema })) - setHasUnsavedChange(false) - } - - return ( -
- -
    - - {(record) => ( -
  • - - -
    {record}
    -
    -
  • - )} -
    -
- -
-
-
-
-
- ) -} diff --git a/solid-save-markdown/src/components/editor/examples/save-markdown/index.ts b/solid-save-markdown/src/components/editor/examples/save-markdown/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-save-markdown/src/components/editor/examples/save-markdown/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/solid-save-markdown/src/components/editor/examples/save-markdown/markdown.ts deleted file mode 100644 index 3f930adad2..0000000000 --- a/solid-save-markdown/src/components/editor/examples/save-markdown/markdown.ts +++ /dev/null @@ -1,26 +0,0 @@ -import rehypeParse from 'rehype-parse' -import rehypeRemark from 'rehype-remark' -import remarkGfm from 'remark-gfm' -import remarkHtml from 'remark-html' -import remarkParse from 'remark-parse' -import remarkStringify from 'remark-stringify' -import { unified } from 'unified' - -export function markdownFromHTML(html: string): string { - return unified() - .use(rehypeParse) - .use(rehypeRemark) - .use(remarkGfm) - .use(remarkStringify) - .processSync(html) - .toString() -} - -export function htmlFromMarkdown(markdown: string): string { - return unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkHtml) - .processSync(markdown) - .toString() -} diff --git a/solid-save-markdown/src/index.tsx b/solid-save-markdown/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-save-markdown/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-save-markdown/tsconfig.app.json b/solid-save-markdown/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-save-markdown/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-save-markdown/tsconfig.json b/solid-save-markdown/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-save-markdown/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-save-markdown/tsconfig.node.json b/solid-save-markdown/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-save-markdown/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-save-markdown/vite.config.ts b/solid-save-markdown/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-save-markdown/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-search/.gitignore b/solid-search/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-search/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-search/README.md b/solid-search/README.md deleted file mode 100644 index dcd1c03410..0000000000 --- a/solid-search/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-search - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-search) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-search) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-search solid-search -cd solid-search -npm install -npm run dev -``` diff --git a/solid-search/index.html b/solid-search/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-search/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-search/package.json b/solid-search/package.json deleted file mode 100644 index e45c16784d..0000000000 --- a/solid-search/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-search", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-search/src/App.tsx b/solid-search/src/App.tsx deleted file mode 100644 index 2f6b77056f..0000000000 --- a/solid-search/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/search' - -export default function App() { - return -} diff --git a/solid-search/src/app.css b/solid-search/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-search/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-search/src/components/editor/examples/search/editor.tsx b/solid-search/src/components/editor/examples/search/editor.tsx deleted file mode 100644 index 1aef7fcdd6..0000000000 --- a/solid-search/src/components/editor/examples/search/editor.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/search/style.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-search' -import { Search } from '../../ui/search' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ - extension, - defaultContent, - }) - - return ( - -
-
- -
-
-
-
- ) -} diff --git a/solid-search/src/components/editor/examples/search/extension.ts b/solid-search/src/components/editor/examples/search/extension.ts deleted file mode 100644 index 10ff13f614..0000000000 --- a/solid-search/src/components/editor/examples/search/extension.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineSearchCommands } from 'prosekit/extensions/search' - -export function defineExtension() { - return union(defineBasicExtension(), defineSearchCommands()) -} - -export type EditorExtension = ReturnType diff --git a/solid-search/src/components/editor/examples/search/index.ts b/solid-search/src/components/editor/examples/search/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-search/src/components/editor/examples/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-search/src/components/editor/sample/sample-doc-search.ts b/solid-search/src/components/editor/sample/sample-doc-search.ts deleted file mode 100644 index c8160cca2a..0000000000 --- a/solid-search/src/components/editor/sample/sample-doc-search.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Baa, baa, black sheep,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Have you any wool?', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Yes, sir, yes, sir,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Three bags full;', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'One for the master,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the dame,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the little boy', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Who lives down the lane.', - }, - ], - }, - ], -} diff --git a/solid-search/src/components/editor/ui/button/button.tsx b/solid-search/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-search/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-search/src/components/editor/ui/button/index.ts b/solid-search/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-search/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-search/src/components/editor/ui/search/index.ts b/solid-search/src/components/editor/ui/search/index.ts deleted file mode 100644 index 0a1f03c720..0000000000 --- a/solid-search/src/components/editor/ui/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Search } from './search' diff --git a/solid-search/src/components/editor/ui/search/search.tsx b/solid-search/src/components/editor/ui/search/search.tsx deleted file mode 100644 index 30ac5d0cfd..0000000000 --- a/solid-search/src/components/editor/ui/search/search.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import { - defineSearchQuery, - type SearchCommandsExtension, -} from 'prosekit/extensions/search' -import { useEditor, useExtension } from 'prosekit/solid' -import { createMemo, createSignal, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function Search(props: { onClose?: VoidFunction }): JSX.Element { - const [showReplace, setShowReplace] = createSignal(false) - const toggleReplace = () => setShowReplace((value) => !value) - - const [searchText, setSearchText] = createSignal('') - const [replaceText, setReplaceText] = createSignal('') - const [caseSensitive, setCaseSensitive] = createSignal(false) - const [wholeWord, setWholeWord] = createSignal(false) - const [regexp, setRegexp] = createSignal(false) - const [literal, setLiteral] = createSignal(false) - - const extension = createMemo(() => { - if (!searchText()) { - return null - } - return defineSearchQuery({ - search: searchText(), - replace: replaceText(), - caseSensitive: caseSensitive(), - wholeWord: wholeWord(), - regexp: regexp(), - literal: literal(), - }) - }) - - useExtension(extension) - - const editor = useEditor() - - const handleSearchKeyDown = (event: KeyboardEvent) => { - if (isEnter(event)) { - event.preventDefault() - editor().commands.findNext() - } else if (isShiftEnter(event)) { - event.preventDefault() - editor().commands.findPrev() - } - } - - const handleReplaceKeyDown = (event: KeyboardEvent) => { - if (isEnter(event)) { - event.preventDefault() - editor().commands.replaceNext() - } else if (isShiftEnter(event)) { - event.preventDefault() - editor().commands.replaceAll() - } - } - - return ( -
- - setSearchText(event.currentTarget.value)} - onKeyDown={handleSearchKeyDown} - class="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" - /> -
- - - - - - - -
- {showReplace() && ( - setReplaceText(event.currentTarget.value)} - onKeyDown={handleReplaceKeyDown} - class="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" - /> - )} - {showReplace() && ( -
- - -
- )} -
- ) -} - -function isEnter(event: KeyboardEvent) { - return ( - event.key === 'Enter' && - !event.shiftKey && - !event.metaKey && - !event.altKey && - !event.ctrlKey && - !event.isComposing - ) -} - -function isShiftEnter(event: KeyboardEvent) { - return ( - event.key === 'Enter' && - event.shiftKey && - !event.metaKey && - !event.altKey && - !event.ctrlKey && - !event.isComposing - ) -} diff --git a/solid-search/src/index.tsx b/solid-search/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-search/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-search/tsconfig.app.json b/solid-search/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-search/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-search/tsconfig.json b/solid-search/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-search/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-search/tsconfig.node.json b/solid-search/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-search/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-search/vite.config.ts b/solid-search/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-search/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-slash-menu/.gitignore b/solid-slash-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-slash-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-slash-menu/README.md b/solid-slash-menu/README.md deleted file mode 100644 index 2745cf76bb..0000000000 --- a/solid-slash-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-slash-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-slash-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-slash-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-slash-menu solid-slash-menu -cd solid-slash-menu -npm install -npm run dev -``` diff --git a/solid-slash-menu/index.html b/solid-slash-menu/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-slash-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-slash-menu/package.json b/solid-slash-menu/package.json deleted file mode 100644 index b2b2b7fe34..0000000000 --- a/solid-slash-menu/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-slash-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-slash-menu/src/App.tsx b/solid-slash-menu/src/App.tsx deleted file mode 100644 index cf430661be..0000000000 --- a/solid-slash-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/slash-menu' - -export default function App() { - return -} diff --git a/solid-slash-menu/src/app.css b/solid-slash-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-slash-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-slash-menu/src/components/editor/examples/slash-menu/editor.tsx b/solid-slash-menu/src/components/editor/examples/slash-menu/editor.tsx deleted file mode 100644 index d7d2bede2d..0000000000 --- a/solid-slash-menu/src/components/editor/examples/slash-menu/editor.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { SlashMenu } from '../../ui/slash-menu' - -import { defineExtension } from './extension' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/solid-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/solid-slash-menu/src/components/editor/examples/slash-menu/extension.ts deleted file mode 100644 index 0edda60136..0000000000 --- a/solid-slash-menu/src/components/editor/examples/slash-menu/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-slash-menu/src/components/editor/examples/slash-menu/index.ts b/solid-slash-menu/src/components/editor/examples/slash-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-slash-menu/src/components/editor/examples/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-slash-menu/src/components/editor/ui/slash-menu/index.ts b/solid-slash-menu/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index b7f6969c32..0000000000 --- a/solid-slash-menu/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu' diff --git a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx deleted file mode 100644 index aae5f3dc6b..0000000000 --- a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { AutocompleteEmpty } from 'prosekit/solid/autocomplete' -import type { JSX } from 'solid-js' - -export default function SlashMenuEmpty(): JSX.Element { - return ( - - No results - - ) -} diff --git a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx deleted file mode 100644 index 9d8101d019..0000000000 --- a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { AutocompleteItem } from 'prosekit/solid/autocomplete' -import { Show, type JSX } from 'solid-js' - -export default function SlashMenuItem(props: { - label: string - kbd?: string - onSelect: () => void -}): JSX.Element { - return ( - - {props.label} - - - {props.kbd} - - - - ) -} diff --git a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx deleted file mode 100644 index c7090d7f36..0000000000 --- a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind } from 'prosekit/core' -import { useEditor } from 'prosekit/solid' -import { - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/solid/autocomplete' -import type { JSX } from 'solid-js' - -import SlashMenuEmpty from './slash-menu-empty' -import SlashMenuItem from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?() - - return ( - - - -
- editor().commands.setParagraph()} - /> - - editor().commands.setHeading({ level: 1 })} - /> - - editor().commands.setHeading({ level: 2 })} - /> - - editor().commands.setHeading({ level: 3 })} - /> - - editor().commands.wrapInList({ kind: 'bullet' })} - /> - - editor().commands.wrapInList({ kind: 'ordered' })} - /> - - editor().commands.wrapInList({ kind: 'task' })} - /> - - editor().commands.wrapInList({ kind: 'toggle' })} - /> - - editor().commands.setBlockquote()} - /> - - editor().commands.insertTable({ row: 3, col: 3 })} - /> - - editor().commands.insertHorizontalRule()} - /> - - editor().commands.setCodeBlock()} - /> - - -
-
-
-
- ) -} diff --git a/solid-slash-menu/src/index.tsx b/solid-slash-menu/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-slash-menu/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-slash-menu/tsconfig.app.json b/solid-slash-menu/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-slash-menu/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-slash-menu/tsconfig.json b/solid-slash-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-slash-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-slash-menu/tsconfig.node.json b/solid-slash-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-slash-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-slash-menu/vite.config.ts b/solid-slash-menu/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-slash-menu/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-strike/.gitignore b/solid-strike/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-strike/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-strike/README.md b/solid-strike/README.md deleted file mode 100644 index 4d17f223fe..0000000000 --- a/solid-strike/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-strike - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-strike) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-strike) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-strike solid-strike -cd solid-strike -npm install -npm run dev -``` diff --git a/solid-strike/index.html b/solid-strike/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-strike/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-strike/package.json b/solid-strike/package.json deleted file mode 100644 index 07a4942dc6..0000000000 --- a/solid-strike/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-strike", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-strike/src/App.tsx b/solid-strike/src/App.tsx deleted file mode 100644 index 497a57c0d8..0000000000 --- a/solid-strike/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/strike' - -export default function App() { - return -} diff --git a/solid-strike/src/app.css b/solid-strike/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-strike/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-strike/src/components/editor/examples/strike/editor.tsx b/solid-strike/src/components/editor/examples/strike/editor.tsx deleted file mode 100644 index cbf49c22df..0000000000 --- a/solid-strike/src/components/editor/examples/strike/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-strike' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-strike/src/components/editor/examples/strike/extension.ts b/solid-strike/src/components/editor/examples/strike/extension.ts deleted file mode 100644 index c013303ccc..0000000000 --- a/solid-strike/src/components/editor/examples/strike/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineStrike(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-strike/src/components/editor/examples/strike/index.ts b/solid-strike/src/components/editor/examples/strike/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-strike/src/components/editor/examples/strike/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-strike/src/components/editor/examples/strike/toolbar.tsx b/solid-strike/src/components/editor/examples/strike/toolbar.tsx deleted file mode 100644 index 1b49d9cf93..0000000000 --- a/solid-strike/src/components/editor/examples/strike/toolbar.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - strike: { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - }, - } -} - -export default function Toolbar(): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- -
- ) -} diff --git a/solid-strike/src/components/editor/sample/sample-doc-strike.ts b/solid-strike/src/components/editor/sample/sample-doc-strike.ts deleted file mode 100644 index 2e025e9b02..0000000000 --- a/solid-strike/src/components/editor/sample/sample-doc-strike.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'This is strike', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/solid-strike/src/components/editor/ui/button/button.tsx b/solid-strike/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-strike/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-strike/src/components/editor/ui/button/index.ts b/solid-strike/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-strike/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-strike/src/index.tsx b/solid-strike/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-strike/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-strike/tsconfig.app.json b/solid-strike/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-strike/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-strike/tsconfig.json b/solid-strike/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-strike/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-strike/tsconfig.node.json b/solid-strike/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-strike/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-strike/vite.config.ts b/solid-strike/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-strike/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-sub-sup/.gitignore b/solid-sub-sup/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-sub-sup/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-sub-sup/README.md b/solid-sub-sup/README.md deleted file mode 100644 index df2195fdc0..0000000000 --- a/solid-sub-sup/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-sub-sup - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-sub-sup) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-sub-sup) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-sub-sup solid-sub-sup -cd solid-sub-sup -npm install -npm run dev -``` diff --git a/solid-sub-sup/index.html b/solid-sub-sup/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-sub-sup/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-sub-sup/package.json b/solid-sub-sup/package.json deleted file mode 100644 index 31a570e274..0000000000 --- a/solid-sub-sup/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-sub-sup", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-sub-sup/src/App.tsx b/solid-sub-sup/src/App.tsx deleted file mode 100644 index 48e43d6423..0000000000 --- a/solid-sub-sup/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/sub-sup' - -export default function App() { - return -} diff --git a/solid-sub-sup/src/app.css b/solid-sub-sup/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-sub-sup/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-sub-sup/src/components/editor/examples/sub-sup/editor.tsx b/solid-sub-sup/src/components/editor/examples/sub-sup/editor.tsx deleted file mode 100644 index 2ed42e8a55..0000000000 --- a/solid-sub-sup/src/components/editor/examples/sub-sup/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-sub-sup' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/solid-sub-sup/src/components/editor/examples/sub-sup/extension.ts deleted file mode 100644 index bd67245f86..0000000000 --- a/solid-sub-sup/src/components/editor/examples/sub-sup/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineMarkInputRule } from 'prosekit/extensions/input-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineSubscript } from 'prosekit/extensions/subscript' -import { defineSuperscript } from 'prosekit/extensions/superscript' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineSubscript(), - defineSuperscript(), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ - : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, - type: 'subscript', - }), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ - : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, - type: 'superscript', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-sub-sup/src/components/editor/examples/sub-sup/index.ts b/solid-sub-sup/src/components/editor/examples/sub-sup/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-sub-sup/src/components/editor/examples/sub-sup/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx b/solid-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx deleted file mode 100644 index c8af70b72c..0000000000 --- a/solid-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function getToolbarItems(editor: Editor) { - return { - subscript: { - isActive: editor.marks.subscript.isActive(), - canExec: editor.commands.toggleSubscript.canExec(), - command: () => editor.commands.toggleSubscript(), - }, - superscript: { - isActive: editor.marks.superscript.isActive(), - canExec: editor.commands.toggleSuperscript.canExec(), - command: () => editor.commands.toggleSuperscript(), - }, - } -} - -export default function Toolbar(): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - -
- ) -} diff --git a/solid-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/solid-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts deleted file mode 100644 index 011be750dc..0000000000 --- a/solid-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'H', - }, - { - type: 'text', - marks: [ - { - type: 'subscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: 'O is water. x', - }, - { - type: 'text', - marks: [ - { - type: 'superscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: ' is a square.', - }, - ], - }, - ], -} diff --git a/solid-sub-sup/src/components/editor/ui/button/button.tsx b/solid-sub-sup/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-sub-sup/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-sub-sup/src/components/editor/ui/button/index.ts b/solid-sub-sup/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-sub-sup/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-sub-sup/src/index.tsx b/solid-sub-sup/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-sub-sup/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-sub-sup/tsconfig.app.json b/solid-sub-sup/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-sub-sup/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-sub-sup/tsconfig.json b/solid-sub-sup/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-sub-sup/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-sub-sup/tsconfig.node.json b/solid-sub-sup/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-sub-sup/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-sub-sup/vite.config.ts b/solid-sub-sup/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-sub-sup/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-table/.gitignore b/solid-table/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-table/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-table/README.md b/solid-table/README.md deleted file mode 100644 index ff407bb97d..0000000000 --- a/solid-table/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-table - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-table) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-table) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-table solid-table -cd solid-table -npm install -npm run dev -``` diff --git a/solid-table/index.html b/solid-table/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-table/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-table/package.json b/solid-table/package.json deleted file mode 100644 index 3a08f98662..0000000000 --- a/solid-table/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-table", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-table/src/App.tsx b/solid-table/src/App.tsx deleted file mode 100644 index 9d9d957adb..0000000000 --- a/solid-table/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/table' - -export default function App() { - return -} diff --git a/solid-table/src/app.css b/solid-table/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-table/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-table/src/components/editor/examples/table/editor.tsx b/solid-table/src/components/editor/examples/table/editor.tsx deleted file mode 100644 index b8b4f1cef1..0000000000 --- a/solid-table/src/components/editor/examples/table/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-table' -import { TableHandle } from '../../ui/table-handle' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/solid-table/src/components/editor/examples/table/extension.ts b/solid-table/src/components/editor/examples/table/extension.ts deleted file mode 100644 index ee7b142041..0000000000 --- a/solid-table/src/components/editor/examples/table/extension.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineTable(), - defineHistory(), - defineGapCursor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-table/src/components/editor/examples/table/index.ts b/solid-table/src/components/editor/examples/table/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-table/src/components/editor/examples/table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-table/src/components/editor/sample/sample-doc-table.ts b/solid-table/src/components/editor/sample/sample-doc-table.ts deleted file mode 100644 index c737121672..0000000000 --- a/solid-table/src/components/editor/sample/sample-doc-table.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D1', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D2', - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], -} diff --git a/solid-table/src/components/editor/ui/table-handle/index.ts b/solid-table/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index f8b273396e..0000000000 --- a/solid-table/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle' diff --git a/solid-table/src/components/editor/ui/table-handle/table-handle.tsx b/solid-table/src/components/editor/ui/table-handle/table-handle.tsx deleted file mode 100644 index 463f4d3657..0000000000 --- a/solid-table/src/components/editor/ui/table-handle/table-handle.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import type { Editor } from 'prosekit/core' -import type { TableExtension } from 'prosekit/extensions/table' -import { useEditorDerivedValue } from 'prosekit/solid' -import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/solid/menu' -import { - TableHandleColumnMenuRoot, - TableHandleColumnMenuTrigger, - TableHandleColumnPopup, - TableHandleColumnPositioner, - TableHandleDragPreview, - TableHandleDropIndicator, - TableHandleRoot, - TableHandleRowMenuRoot, - TableHandleRowMenuTrigger, - TableHandleRowPopup, - TableHandleRowPositioner, -} from 'prosekit/solid/table-handle' -import { Show, type JSX } from 'solid-js' - -function getTableHandleState(editor: Editor) { - return { - addTableColumnBefore: { - canExec: editor.commands.addTableColumnBefore.canExec(), - command: () => editor.commands.addTableColumnBefore(), - }, - addTableColumnAfter: { - canExec: editor.commands.addTableColumnAfter.canExec(), - command: () => editor.commands.addTableColumnAfter(), - }, - deleteCellSelection: { - canExec: editor.commands.deleteCellSelection.canExec(), - command: () => editor.commands.deleteCellSelection(), - }, - deleteTableColumn: { - canExec: editor.commands.deleteTableColumn.canExec(), - command: () => editor.commands.deleteTableColumn(), - }, - addTableRowAbove: { - canExec: editor.commands.addTableRowAbove.canExec(), - command: () => editor.commands.addTableRowAbove(), - }, - addTableRowBelow: { - canExec: editor.commands.addTableRowBelow.canExec(), - command: () => editor.commands.addTableRowBelow(), - }, - deleteTableRow: { - canExec: editor.commands.deleteTableRow.canExec(), - command: () => editor.commands.deleteTableRow(), - }, - deleteTable: { - canExec: editor.commands.deleteTable.canExec(), - command: () => editor.commands.deleteTable(), - }, - } -} - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function TableHandle(props: Props): JSX.Element { - const state = useEditorDerivedValue(getTableHandleState) - - return ( - - - - - - - -
-
- - - - state().addTableColumnBefore.command()} - > - Insert Left - - - - state().addTableColumnAfter.command()} - > - Insert Right - - - - state().deleteCellSelection.command()} - > - Clear Contents - - Del - - - - - state().deleteTableColumn.command()} - > - Delete Column - - - - state().deleteTable.command()} - > - Delete Table - - - - -
-
-
- - - - -
-
- - - - state().addTableRowAbove.command()} - > - Insert Above - - - - state().addTableRowBelow.command()} - > - Insert Below - - - - state().deleteCellSelection.command()} - > - Clear Contents - - Del - - - - - state().deleteTableRow.command()} - > - Delete Row - - - - state().deleteTable.command()} - > - Delete Table - - - - -
-
-
-
- ) -} diff --git a/solid-table/src/index.tsx b/solid-table/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-table/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-table/tsconfig.app.json b/solid-table/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-table/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-table/tsconfig.json b/solid-table/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-table/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-table/tsconfig.node.json b/solid-table/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-table/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-table/vite.config.ts b/solid-table/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-table/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-temml/.gitignore b/solid-temml/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-temml/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-temml/README.md b/solid-temml/README.md deleted file mode 100644 index b5e21e97d5..0000000000 --- a/solid-temml/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-temml - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-temml) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-temml) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-temml solid-temml -cd solid-temml -npm install -npm run dev -``` diff --git a/solid-temml/index.html b/solid-temml/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-temml/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-temml/package.json b/solid-temml/package.json deleted file mode 100644 index a145b7eba5..0000000000 --- a/solid-temml/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-solid-temml", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13", - "temml": "^0.13.2" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-temml/src/App.tsx b/solid-temml/src/App.tsx deleted file mode 100644 index f6ec50ec0e..0000000000 --- a/solid-temml/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/temml' - -export default function App() { - return -} diff --git a/solid-temml/src/app.css b/solid-temml/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-temml/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-temml/src/components/editor/examples/temml/editor.tsx b/solid-temml/src/components/editor/examples/temml/editor.tsx deleted file mode 100644 index 11c41d38d9..0000000000 --- a/solid-temml/src/components/editor/examples/temml/editor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-tex' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
-
-
-
- ) -} diff --git a/solid-temml/src/components/editor/examples/temml/extension.ts b/solid-temml/src/components/editor/examples/temml/extension.ts deleted file mode 100644 index 2fcd2ffa42..0000000000 --- a/solid-temml/src/components/editor/examples/temml/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderTemmlMathBlock, renderTemmlMathInline } from '../../sample/temml' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderTemmlMathBlock, - renderMathInline: renderTemmlMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-temml/src/components/editor/examples/temml/index.ts b/solid-temml/src/components/editor/examples/temml/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-temml/src/components/editor/examples/temml/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-temml/src/components/editor/sample/sample-doc-tex.ts b/solid-temml/src/components/editor/sample/sample-doc-tex.ts deleted file mode 100644 index 21ccf3e94e..0000000000 --- a/solid-temml/src/components/editor/sample/sample-doc-tex.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Inline equations' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Block equations' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: 'The Gaussian integral:' }], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - ], -} diff --git a/solid-temml/src/components/editor/sample/temml.ts b/solid-temml/src/components/editor/sample/temml.ts deleted file mode 100644 index 4cbe764f93..0000000000 --- a/solid-temml/src/components/editor/sample/temml.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Temml from 'temml' - -export function renderTemmlMathBlock(text: string, element: HTMLElement) { - Temml.render(text, element, { - displayMode: true, - annotate: true, - throwOnError: false, - }) -} - -export function renderTemmlMathInline(text: string, element: HTMLElement) { - Temml.render(text, element, { - displayMode: false, - annotate: true, - throwOnError: false, - }) -} diff --git a/solid-temml/src/index.tsx b/solid-temml/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-temml/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-temml/tsconfig.app.json b/solid-temml/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-temml/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-temml/tsconfig.json b/solid-temml/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-temml/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-temml/tsconfig.node.json b/solid-temml/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-temml/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-temml/vite.config.ts b/solid-temml/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-temml/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-text-align/.gitignore b/solid-text-align/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-text-align/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-text-align/README.md b/solid-text-align/README.md deleted file mode 100644 index 7a75a58ede..0000000000 --- a/solid-text-align/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-text-align - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-text-align) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-text-align) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-text-align solid-text-align -cd solid-text-align -npm install -npm run dev -``` diff --git a/solid-text-align/index.html b/solid-text-align/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-text-align/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-text-align/package.json b/solid-text-align/package.json deleted file mode 100644 index 1a71d4ce59..0000000000 --- a/solid-text-align/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-text-align", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-text-align/src/App.tsx b/solid-text-align/src/App.tsx deleted file mode 100644 index 0c049df602..0000000000 --- a/solid-text-align/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/text-align' - -export default function App() { - return -} diff --git a/solid-text-align/src/app.css b/solid-text-align/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-text-align/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-text-align/src/components/editor/examples/text-align/editor.tsx b/solid-text-align/src/components/editor/examples/text-align/editor.tsx deleted file mode 100644 index 2c8c3bbfa4..0000000000 --- a/solid-text-align/src/components/editor/examples/text-align/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-text-align' - -import { defineExtension } from './extension' -import Toolbar from './toolbar' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-text-align/src/components/editor/examples/text-align/extension.ts b/solid-text-align/src/components/editor/examples/text-align/extension.ts deleted file mode 100644 index f1ae44dc7c..0000000000 --- a/solid-text-align/src/components/editor/examples/text-align/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineTextAlign } from 'prosekit/extensions/text-align' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextAlign({ types: ['paragraph', 'heading'] }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-text-align/src/components/editor/examples/text-align/index.ts b/solid-text-align/src/components/editor/examples/text-align/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-text-align/src/components/editor/examples/text-align/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-text-align/src/components/editor/examples/text-align/toolbar.tsx b/solid-text-align/src/components/editor/examples/text-align/toolbar.tsx deleted file mode 100644 index 8c11774886..0000000000 --- a/solid-text-align/src/components/editor/examples/text-align/toolbar.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -function isTextAlignActive(editor: Editor, value: string) { - return Object.values(editor.nodes).some((node) => { - // @ts-expect-error textAlign may not be available on every node - return node.isActive({ textAlign: value }) - }) -} - -function getToolbarItems(editor: Editor) { - return { - left: { - isActive: isTextAlignActive(editor, 'left'), - canExec: editor.commands.setTextAlign.canExec('left'), - command: () => editor.commands.setTextAlign('left'), - }, - center: { - isActive: isTextAlignActive(editor, 'center'), - canExec: editor.commands.setTextAlign.canExec('center'), - command: () => editor.commands.setTextAlign('center'), - }, - right: { - isActive: isTextAlignActive(editor, 'right'), - canExec: editor.commands.setTextAlign.canExec('right'), - command: () => editor.commands.setTextAlign('right'), - }, - justify: { - isActive: isTextAlignActive(editor, 'justify'), - canExec: editor.commands.setTextAlign.canExec('justify'), - command: () => editor.commands.setTextAlign('justify'), - }, - } -} - -export default function Toolbar(): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - - - - - - -
- ) -} diff --git a/solid-text-align/src/components/editor/sample/sample-doc-text-align.ts b/solid-text-align/src/components/editor/sample/sample-doc-text-align.ts deleted file mode 100644 index 0724cea4f7..0000000000 --- a/solid-text-align/src/components/editor/sample/sample-doc-text-align.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Heading', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'left', - }, - content: [ - { - type: 'text', - text: 'First paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Second paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'right', - }, - content: [ - { - type: 'text', - text: 'Third paragraph', - }, - ], - }, - ], -} diff --git a/solid-text-align/src/components/editor/ui/button/button.tsx b/solid-text-align/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-text-align/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-text-align/src/components/editor/ui/button/index.ts b/solid-text-align/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-text-align/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-text-align/src/index.tsx b/solid-text-align/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-text-align/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-text-align/tsconfig.app.json b/solid-text-align/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-text-align/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-text-align/tsconfig.json b/solid-text-align/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-text-align/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-text-align/tsconfig.node.json b/solid-text-align/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-text-align/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-text-align/vite.config.ts b/solid-text-align/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-text-align/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-text-color/.gitignore b/solid-text-color/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-text-color/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-text-color/README.md b/solid-text-color/README.md deleted file mode 100644 index 894ae982fe..0000000000 --- a/solid-text-color/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-text-color - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-text-color) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-text-color) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-text-color solid-text-color -cd solid-text-color -npm install -npm run dev -``` diff --git a/solid-text-color/index.html b/solid-text-color/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-text-color/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-text-color/package.json b/solid-text-color/package.json deleted file mode 100644 index caeb7d290b..0000000000 --- a/solid-text-color/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-text-color", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-text-color/src/App.tsx b/solid-text-color/src/App.tsx deleted file mode 100644 index 1225de322a..0000000000 --- a/solid-text-color/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/text-color' - -export default function App() { - return -} diff --git a/solid-text-color/src/app.css b/solid-text-color/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-text-color/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-text-color/src/components/editor/examples/text-color/editor.tsx b/solid-text-color/src/components/editor/examples/text-color/editor.tsx deleted file mode 100644 index ee7b9f6b11..0000000000 --- a/solid-text-color/src/components/editor/examples/text-color/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-text-color' - -import { defineExtension } from './extension' -import InlineMenu from './inline-menu' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/solid-text-color/src/components/editor/examples/text-color/extension.ts b/solid-text-color/src/components/editor/examples/text-color/extension.ts deleted file mode 100644 index d35d9d5c22..0000000000 --- a/solid-text-color/src/components/editor/examples/text-color/extension.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineBackgroundColor } from 'prosekit/extensions/background-color' -import { defineTextColor } from 'prosekit/extensions/text-color' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextColor(), - defineBackgroundColor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-text-color/src/components/editor/examples/text-color/index.ts b/solid-text-color/src/components/editor/examples/text-color/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-text-color/src/components/editor/examples/text-color/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-text-color/src/components/editor/examples/text-color/inline-menu.tsx b/solid-text-color/src/components/editor/examples/text-color/inline-menu.tsx deleted file mode 100644 index c85523bba7..0000000000 --- a/solid-text-color/src/components/editor/examples/text-color/inline-menu.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import type { Editor, Keymap } from 'prosekit/core' -import { useEditorDerivedValue, useKeymap } from 'prosekit/solid' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/solid/inline-popover' -import { createSignal, For, type JSX } from 'solid-js' - -import { Button } from '../../ui/button' - -import type { EditorExtension } from './extension' - -const textColors = [ - { label: 'Gray', value: '#9ca3af' }, - { label: 'Brown', value: '#92400e' }, - { label: 'Orange', value: '#ea580c' }, - { label: 'Yellow', value: '#ca8a04' }, - { label: 'Green', value: '#16a34a' }, - { label: 'Blue', value: '#2563eb' }, - { label: 'Purple', value: '#9333ea' }, - { label: 'Magenta', value: '#c026d3' }, - { label: 'Red', value: '#dc2626' }, -] - -const backgroundColors = [ - { label: 'Gray', value: '#f3f4f6' }, - { label: 'Brown', value: '#fef3c7' }, - { label: 'Orange', value: '#ffedd5' }, - { label: 'Yellow', value: '#fef9c3' }, - { label: 'Green', value: '#d1fae5' }, - { label: 'Blue', value: '#dbeafe' }, - { label: 'Purple', value: '#e9d5ff' }, - { label: 'Pink', value: '#fce7f3' }, - { label: 'Red', value: '#fecaca' }, -] - -function getTextColorState(editor: Editor) { - return [ - { - label: 'Default', - value: 'currentColor', - isActive: !editor.marks.textColor.isActive(), - onClick: () => editor.commands.removeTextColor(), - }, - ].concat( - textColors.map((color) => ({ - label: color.label, - value: color.value, - isActive: editor.marks.textColor.isActive({ color: color.value }), - onClick: () => editor.commands.addTextColor({ color: color.value }), - })), - ) -} - -function getBackgroundColorState(editor: Editor) { - return [ - { - label: 'Default', - value: 'canvas', - isActive: !editor.marks.backgroundColor.isActive(), - onClick: () => editor.commands.removeBackgroundColor(), - }, - ].concat( - backgroundColors.map((color) => ({ - label: color.label, - value: color.value, - isActive: editor.marks.backgroundColor.isActive({ color: color.value }), - onClick: () => editor.commands.addBackgroundColor({ color: color.value }), - })), - ) -} - -export default function InlineMenu(): JSX.Element { - const textColorState = useEditorDerivedValue(getTextColorState) - const backgroundColorState = useEditorDerivedValue(getBackgroundColorState) - const [open, setOpen] = createSignal(false) - - const keymap: () => Keymap = () => ({ - Escape: () => { - if (open()) { - setOpen(false) - return true - } - return false - }, - }) - - useKeymap(keymap) - - return ( - setOpen(event.detail)} - > - - -
-
-
Text color
-
- - {(color) => ( - - )} - -
-
-
-
Background color
-
- - {(color) => ( - - )} - -
-
-
-
-
-
- ) -} diff --git a/solid-text-color/src/components/editor/sample/sample-doc-text-color.ts b/solid-text-color/src/components/editor/sample/sample-doc-text-color.ts deleted file mode 100644 index a4efe4308d..0000000000 --- a/solid-text-color/src/components/editor/sample/sample-doc-text-color.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#ef4444', - }, - }, - ], - text: 'Select', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#f97316', - }, - }, - ], - text: 'some', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#eab308', - }, - }, - ], - text: 'text', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#22c55e', - }, - }, - ], - text: 'to', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#3b82f6', - }, - }, - ], - text: 'change', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#6366f1', - }, - }, - ], - text: 'the', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#a855f7', - }, - }, - ], - text: 'color', - }, - ], - }, - ], -} diff --git a/solid-text-color/src/components/editor/ui/button/button.tsx b/solid-text-color/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-text-color/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-text-color/src/components/editor/ui/button/index.ts b/solid-text-color/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-text-color/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-text-color/src/index.tsx b/solid-text-color/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-text-color/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-text-color/tsconfig.app.json b/solid-text-color/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-text-color/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-text-color/tsconfig.json b/solid-text-color/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-text-color/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-text-color/tsconfig.node.json b/solid-text-color/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-text-color/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-text-color/vite.config.ts b/solid-text-color/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-text-color/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-toolbar/.gitignore b/solid-toolbar/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-toolbar/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-toolbar/README.md b/solid-toolbar/README.md deleted file mode 100644 index 2c16e8d66e..0000000000 --- a/solid-toolbar/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-toolbar - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-toolbar) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-toolbar) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-toolbar solid-toolbar -cd solid-toolbar -npm install -npm run dev -``` diff --git a/solid-toolbar/index.html b/solid-toolbar/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-toolbar/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-toolbar/package.json b/solid-toolbar/package.json deleted file mode 100644 index e1bf875de4..0000000000 --- a/solid-toolbar/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-toolbar", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-toolbar/src/App.tsx b/solid-toolbar/src/App.tsx deleted file mode 100644 index 72699e4f11..0000000000 --- a/solid-toolbar/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/toolbar' - -export default function App() { - return -} diff --git a/solid-toolbar/src/app.css b/solid-toolbar/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-toolbar/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-toolbar/src/components/editor/examples/toolbar/editor.tsx b/solid-toolbar/src/components/editor/examples/toolbar/editor.tsx deleted file mode 100644 index 8523725ffd..0000000000 --- a/solid-toolbar/src/components/editor/examples/toolbar/editor.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleUploader } from '../../sample/sample-uploader' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-toolbar/src/components/editor/examples/toolbar/extension.ts b/solid-toolbar/src/components/editor/examples/toolbar/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/solid-toolbar/src/components/editor/examples/toolbar/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/solid-toolbar/src/components/editor/examples/toolbar/index.ts b/solid-toolbar/src/components/editor/examples/toolbar/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-toolbar/src/components/editor/examples/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-toolbar/src/components/editor/sample/sample-uploader.ts b/solid-toolbar/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/solid-toolbar/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/solid-toolbar/src/components/editor/ui/button/button.tsx b/solid-toolbar/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-toolbar/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-toolbar/src/components/editor/ui/button/index.ts b/solid-toolbar/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-toolbar/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/solid-toolbar/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-toolbar/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-toolbar/src/components/editor/ui/toolbar/index.ts b/solid-toolbar/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-toolbar/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-toolbar/src/components/editor/ui/toolbar/toolbar.tsx b/solid-toolbar/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-toolbar/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-toolbar/src/index.tsx b/solid-toolbar/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-toolbar/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-toolbar/tsconfig.app.json b/solid-toolbar/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-toolbar/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-toolbar/tsconfig.json b/solid-toolbar/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-toolbar/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-toolbar/tsconfig.node.json b/solid-toolbar/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-toolbar/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-toolbar/vite.config.ts b/solid-toolbar/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-toolbar/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-typography/.gitignore b/solid-typography/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-typography/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-typography/README.md b/solid-typography/README.md deleted file mode 100644 index 00298fb7ce..0000000000 --- a/solid-typography/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-typography - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-typography) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-typography) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-typography solid-typography -cd solid-typography -npm install -npm run dev -``` diff --git a/solid-typography/index.html b/solid-typography/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-typography/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-typography/package.json b/solid-typography/package.json deleted file mode 100644 index df819bc69a..0000000000 --- a/solid-typography/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-solid-typography", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-typography/src/App.tsx b/solid-typography/src/App.tsx deleted file mode 100644 index e1a59aa483..0000000000 --- a/solid-typography/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/typography' - -export default function App() { - return -} diff --git a/solid-typography/src/app.css b/solid-typography/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-typography/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-typography/src/components/editor/examples/typography/editor.tsx b/solid-typography/src/components/editor/examples/typography/editor.tsx deleted file mode 100644 index 219dc02cc6..0000000000 --- a/solid-typography/src/components/editor/examples/typography/editor.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-typography' -import { BlockHandle } from '../../ui/block-handle' -import { DropIndicator } from '../../ui/drop-indicator' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/solid-typography/src/components/editor/examples/typography/extension.ts b/solid-typography/src/components/editor/examples/typography/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/solid-typography/src/components/editor/examples/typography/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-typography/src/components/editor/examples/typography/index.ts b/solid-typography/src/components/editor/examples/typography/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-typography/src/components/editor/examples/typography/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-typography/src/components/editor/sample/katex.ts b/solid-typography/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/solid-typography/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/solid-typography/src/components/editor/sample/sample-doc-typography.ts b/solid-typography/src/components/editor/sample/sample-doc-typography.ts deleted file mode 100644 index db18b8155c..0000000000 --- a/solid-typography/src/components/editor/sample/sample-doc-typography.ts +++ /dev/null @@ -1,693 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'ProseKit Typography', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This example shows the typography styles provided by ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'prosekit/basic/typography.css', - }, - { - type: 'text', - text: '.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Inline marks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Text can be formatted in different ways: ', - }, - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'bold text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'italic text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'underlined text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'strikethrough text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'inline code', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://example.com', - target: null, - rel: null, - }, - }, - ], - text: 'links', - }, - { - type: 'text', - text: ',', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'and hard breaks (Shift+Enter).', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Headings', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Heading 1', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Heading 2', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Heading 3', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 4, - }, - content: [ - { - type: 'text', - text: 'Heading 4', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 5, - }, - content: [ - { - type: 'text', - text: 'Heading 5', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 6, - }, - content: [ - { - type: 'text', - text: 'Heading 6', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Lists', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here are different types of lists:', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 1', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 2', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item A', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item B', - }, - ], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'First ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Second ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: true, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Completed task', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Pending task', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Blockquotes', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: '', - }, - content: [ - { - type: 'text', - text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Horizontal Rule', - }, - ], - }, - { - type: 'horizontalRule', - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blurred/640x360/42', - }, - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Tables', - }, - ], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 1', - }, - ], - }, - ], - }, - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 3', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 4', - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Math', - }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Inline math like Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text.' }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Block-level equations are displayed on their own line:', - }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - ], -} diff --git a/solid-typography/src/components/editor/ui/block-handle/block-handle.tsx b/solid-typography/src/components/editor/ui/block-handle/block-handle.tsx deleted file mode 100644 index 95e1693ef6..0000000000 --- a/solid-typography/src/components/editor/ui/block-handle/block-handle.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { - BlockHandleAdd, - BlockHandleDraggable, - BlockHandlePopup, - BlockHandlePositioner, - BlockHandleRoot, -} from 'prosekit/solid/block-handle' -import type { JSX } from 'solid-js' - -interface Props { - dir?: 'ltr' | 'rtl' -} - -export default function BlockHandle(props: Props): JSX.Element { - return ( - - - - -
- - -
- - - - - ) -} diff --git a/solid-typography/src/components/editor/ui/block-handle/index.ts b/solid-typography/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 43efe9ce3f..0000000000 --- a/solid-typography/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle' diff --git a/solid-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/solid-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx deleted file mode 100644 index c5a24c7faa..0000000000 --- a/solid-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { DropIndicator as BaseDropIndicator } from 'prosekit/solid/drop-indicator' -import type { JSX } from 'solid-js' - -export default function DropIndicator(): JSX.Element { - return -} diff --git a/solid-typography/src/components/editor/ui/drop-indicator/index.ts b/solid-typography/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index f8fb7139c4..0000000000 --- a/solid-typography/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator' diff --git a/solid-typography/src/index.tsx b/solid-typography/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-typography/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-typography/tsconfig.app.json b/solid-typography/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-typography/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-typography/tsconfig.json b/solid-typography/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-typography/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-typography/tsconfig.node.json b/solid-typography/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-typography/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-typography/vite.config.ts b/solid-typography/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-typography/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-underline/.gitignore b/solid-underline/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-underline/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-underline/README.md b/solid-underline/README.md deleted file mode 100644 index 19cbc2a06d..0000000000 --- a/solid-underline/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-underline - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-underline) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-underline) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-underline solid-underline -cd solid-underline -npm install -npm run dev -``` diff --git a/solid-underline/index.html b/solid-underline/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-underline/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-underline/package.json b/solid-underline/package.json deleted file mode 100644 index 01c4fae370..0000000000 --- a/solid-underline/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-underline", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-underline/src/App.tsx b/solid-underline/src/App.tsx deleted file mode 100644 index 6a03ee7870..0000000000 --- a/solid-underline/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/underline' - -export default function App() { - return -} diff --git a/solid-underline/src/app.css b/solid-underline/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-underline/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-underline/src/components/editor/examples/underline/editor.tsx b/solid-underline/src/components/editor/examples/underline/editor.tsx deleted file mode 100644 index b4d246969c..0000000000 --- a/solid-underline/src/components/editor/examples/underline/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-underline' -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-underline/src/components/editor/examples/underline/extension.ts b/solid-underline/src/components/editor/examples/underline/extension.ts deleted file mode 100644 index 16a9b58284..0000000000 --- a/solid-underline/src/components/editor/examples/underline/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineUnderline(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-underline/src/components/editor/examples/underline/index.ts b/solid-underline/src/components/editor/examples/underline/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-underline/src/components/editor/examples/underline/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-underline/src/components/editor/sample/sample-doc-underline.ts b/solid-underline/src/components/editor/sample/sample-doc-underline.ts deleted file mode 100644 index 6af561064b..0000000000 --- a/solid-underline/src/components/editor/sample/sample-doc-underline.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'This is underline', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/solid-underline/src/components/editor/ui/button/button.tsx b/solid-underline/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-underline/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-underline/src/components/editor/ui/button/index.ts b/solid-underline/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-underline/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-underline/src/components/editor/ui/image-upload-popover/index.ts b/solid-underline/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-underline/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-underline/src/components/editor/ui/toolbar/index.ts b/solid-underline/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-underline/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-underline/src/components/editor/ui/toolbar/toolbar.tsx b/solid-underline/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-underline/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-underline/src/index.tsx b/solid-underline/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-underline/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-underline/tsconfig.app.json b/solid-underline/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-underline/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-underline/tsconfig.json b/solid-underline/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-underline/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-underline/tsconfig.node.json b/solid-underline/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-underline/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-underline/vite.config.ts b/solid-underline/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-underline/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-unmount/.gitignore b/solid-unmount/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-unmount/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-unmount/README.md b/solid-unmount/README.md deleted file mode 100644 index 5d93fa426e..0000000000 --- a/solid-unmount/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-unmount - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-unmount) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-unmount) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-unmount solid-unmount -cd solid-unmount -npm install -npm run dev -``` diff --git a/solid-unmount/index.html b/solid-unmount/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-unmount/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-unmount/package.json b/solid-unmount/package.json deleted file mode 100644 index d555a4a6d3..0000000000 --- a/solid-unmount/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-unmount", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-unmount/src/App.tsx b/solid-unmount/src/App.tsx deleted file mode 100644 index da35bea56f..0000000000 --- a/solid-unmount/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/unmount' - -export default function App() { - return -} diff --git a/solid-unmount/src/app.css b/solid-unmount/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-unmount/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-unmount/src/components/editor/examples/unmount/editor-component.tsx b/solid-unmount/src/components/editor/examples/unmount/editor-component.tsx deleted file mode 100644 index 9eb7937ed2..0000000000 --- a/solid-unmount/src/components/editor/examples/unmount/editor-component.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { InlineMenu } from '../../ui/inline-menu' - -import ExtensionComponent from './extension-component.tsx' - -export default function EditorComponent(props: { - placeholder: string -}): JSX.Element { - const extension = defineBasicExtension() - const editor = createEditor({ extension }) - - return ( - -
-
-
- -
-
- -
- ) -} diff --git a/solid-unmount/src/components/editor/examples/unmount/editor.tsx b/solid-unmount/src/components/editor/examples/unmount/editor.tsx deleted file mode 100644 index daca583170..0000000000 --- a/solid-unmount/src/components/editor/examples/unmount/editor.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { createSignal, For, type JSX } from 'solid-js' - -import EditorComponent from './editor-component' - -export default function Editor(): JSX.Element { - let nextKey = 1 - const [editorKeys, setEditorKeys] = createSignal([]) - - const addEditor = () => { - const key = nextKey - nextKey += 1 - setEditorKeys((keys) => [...keys, key]) - } - - const removeEditor = (key: number) => { - setEditorKeys((keys) => keys.filter((k) => k !== key)) - } - - return ( -
-
- - - {(key) => ( - - )} - -
- - {(key) => ( -
- -
- )} -
-
- ) -} diff --git a/solid-unmount/src/components/editor/examples/unmount/extension-component.tsx b/solid-unmount/src/components/editor/examples/unmount/extension-component.tsx deleted file mode 100644 index 7ae8a342a4..0000000000 --- a/solid-unmount/src/components/editor/examples/unmount/extension-component.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { definePlaceholder } from 'prosekit/extensions/placeholder' -import { useExtension } from 'prosekit/solid' -import { createMemo, type JSX } from 'solid-js' - -export default function ExtensionComponent(props: { - placeholder: string -}): JSX.Element { - const extension = createMemo(() => { - return definePlaceholder({ placeholder: props.placeholder }) - }) - - useExtension(extension) - - return null -} diff --git a/solid-unmount/src/components/editor/examples/unmount/index.ts b/solid-unmount/src/components/editor/examples/unmount/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-unmount/src/components/editor/examples/unmount/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-unmount/src/components/editor/ui/button/button.tsx b/solid-unmount/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-unmount/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-unmount/src/components/editor/ui/button/index.ts b/solid-unmount/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-unmount/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-unmount/src/components/editor/ui/inline-menu/index.ts b/solid-unmount/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8ead2b5072..0000000000 --- a/solid-unmount/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu' diff --git a/solid-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx deleted file mode 100644 index d61df6d794..0000000000 --- a/solid-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx +++ /dev/null @@ -1,233 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { LinkAttrs } from 'prosekit/extensions/link' -import type { EditorState } from 'prosekit/pm/state' -import { useEditor, useEditorDerivedValue } from 'prosekit/solid' -import { - InlinePopoverPopup, - InlinePopoverPositioner, - InlinePopoverRoot, -} from 'prosekit/solid/inline-popover' -import { createSignal, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -function getInlineMenuItems(editor: Editor) { - return { - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - link: editor.commands.addLink - ? { - isActive: editor.marks.link.isActive(), - canExec: editor.commands.addLink.canExec({ href: '' }), - command: () => editor.commands.expandLink(), - currentLink: getCurrentLink(editor.state) || '', - } - : undefined, - } -} - -function getCurrentLink(state: EditorState): string | undefined { - const { $from } = state.selection - const marks = $from.marksAcross($from) - if (!marks) { - return - } - for (const mark of marks) { - if (mark.type.name === 'link') { - return (mark.attrs as LinkAttrs).href - } - } -} - -export default function InlineMenu(): JSX.Element { - const editor = useEditor() - const items = useEditorDerivedValue(getInlineMenuItems) - - const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) - const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) - - const handleLinkUpdate = (href?: string) => { - if (href) { - editor().commands.addLink({ href }) - } else { - editor().commands.removeLink() - } - - setLinkMenuOpen(false) - editor().focus() - } - - return ( - <> - { - if (!event.detail) { - setLinkMenuOpen(false) - } - }} - > - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - - - - {(item) => ( - setLinkMenuOpen(event.detail)} - > - - - -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
-
- - - -
-
-
- )} -
- - ) -} diff --git a/solid-unmount/src/index.tsx b/solid-unmount/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-unmount/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-unmount/tsconfig.app.json b/solid-unmount/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-unmount/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-unmount/tsconfig.json b/solid-unmount/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-unmount/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-unmount/tsconfig.node.json b/solid-unmount/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-unmount/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-unmount/vite.config.ts b/solid-unmount/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-unmount/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-user-menu-dynamic/.gitignore b/solid-user-menu-dynamic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-user-menu-dynamic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-user-menu-dynamic/README.md b/solid-user-menu-dynamic/README.md deleted file mode 100644 index 750b82c1d7..0000000000 --- a/solid-user-menu-dynamic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-user-menu-dynamic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-user-menu-dynamic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-user-menu-dynamic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-user-menu-dynamic solid-user-menu-dynamic -cd solid-user-menu-dynamic -npm install -npm run dev -``` diff --git a/solid-user-menu-dynamic/index.html b/solid-user-menu-dynamic/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-user-menu-dynamic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-user-menu-dynamic/package.json b/solid-user-menu-dynamic/package.json deleted file mode 100644 index 6515ef3026..0000000000 --- a/solid-user-menu-dynamic/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-user-menu-dynamic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-user-menu-dynamic/src/App.tsx b/solid-user-menu-dynamic/src/App.tsx deleted file mode 100644 index e3ec0e7b10..0000000000 --- a/solid-user-menu-dynamic/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/user-menu-dynamic' - -export default function App() { - return -} diff --git a/solid-user-menu-dynamic/src/app.css b/solid-user-menu-dynamic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-user-menu-dynamic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx deleted file mode 100644 index 938860e758..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { defineExtension } from './extension' -import UserMenuDynamic from './user-menu-dynamic' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts deleted file mode 100644 index ff2c40b104..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts deleted file mode 100644 index bd8bc313e2..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { createEffect, createSignal } from 'solid-js' - -import type { User } from '../../sample/sample-query-users' -import { queryUsers } from '../../sample/sample-query-users' - -/** - * Simulate a user searching with some delay. - */ -export function useUserQuery( - getQuery: () => string, - getEnabled: () => boolean, -) { - const [users, setUsers] = createSignal([]) - const [loading, setLoading] = createSignal(true) - - createEffect(() => { - const query = getQuery() - const enabled = getEnabled() - - if (!enabled) { - setUsers([]) - return - } - - setLoading(true) - let cancelled = false - - void queryUsers(query).then((filteredUsers) => { - if (cancelled) { - return - } - setUsers(filteredUsers) - setLoading(false) - }) - - return () => { - cancelled = true - } - }) - - return { loading, users } -} diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx deleted file mode 100644 index a9d721e501..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { createSignal, type JSX } from 'solid-js' - -import { UserMenu } from '../../ui/user-menu' - -import { useUserQuery } from './use-user-query' - -export default function UserMenuDynamic(): JSX.Element { - const [query, setQuery] = createSignal('') - const [open, setOpen] = createSignal(false) - - const { loading, users } = useUserQuery(query, open) - - return ( - - ) -} diff --git a/solid-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/solid-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts deleted file mode 100644 index ab78fd5525..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { users } from './sample-user-data' - -export interface User { - id: number - name: string -} - -const connectHandlers: VoidFunction[] = [] -let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' - -/** - * A utility function to simulate different network states. Useful for testing. - * - * @internal - */ -export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { - networkStatus = status - if (status !== 'offline') { - connectHandlers.forEach((handler) => handler()) - connectHandlers.length = 0 - } -} - -/** - * Simulate a user searching with some delay. - */ -export async function queryUsers(query: string): Promise { - if (networkStatus === 'offline') { - await new Promise((resolve) => connectHandlers.push(resolve)) - } - if (networkStatus === 'slow') { - await new Promise((resolve) => setTimeout(resolve, 300)) - } - - const normalizedQuery = query.toLowerCase().trim() - const filteredUsers = users - .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) - .slice(0, 10) - return filteredUsers -} diff --git a/solid-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/solid-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/solid-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/solid-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/solid-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx b/solid-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 61d3cd96d8..0000000000 --- a/solid-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/solid' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/solid/autocomplete' -import { For, type JSX } from 'solid-js' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}): JSX.Element { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor().commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor().commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - - {(user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - )} - -
-
-
-
- ) -} diff --git a/solid-user-menu-dynamic/src/index.tsx b/solid-user-menu-dynamic/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-user-menu-dynamic/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-user-menu-dynamic/tsconfig.app.json b/solid-user-menu-dynamic/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-user-menu-dynamic/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-user-menu-dynamic/tsconfig.json b/solid-user-menu-dynamic/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-user-menu-dynamic/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-user-menu-dynamic/tsconfig.node.json b/solid-user-menu-dynamic/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-user-menu-dynamic/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-user-menu-dynamic/vite.config.ts b/solid-user-menu-dynamic/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-user-menu-dynamic/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-user-menu/.gitignore b/solid-user-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-user-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-user-menu/README.md b/solid-user-menu/README.md deleted file mode 100644 index 51f890d5bb..0000000000 --- a/solid-user-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-user-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-user-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-user-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-user-menu solid-user-menu -cd solid-user-menu -npm install -npm run dev -``` diff --git a/solid-user-menu/index.html b/solid-user-menu/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-user-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-user-menu/package.json b/solid-user-menu/package.json deleted file mode 100644 index 5b2e08ee99..0000000000 --- a/solid-user-menu/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-user-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-user-menu/src/App.tsx b/solid-user-menu/src/App.tsx deleted file mode 100644 index 92fca03d42..0000000000 --- a/solid-user-menu/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/user-menu' - -export default function App() { - return -} diff --git a/solid-user-menu/src/app.css b/solid-user-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-user-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-user-menu/src/components/editor/examples/user-menu/editor.tsx b/solid-user-menu/src/components/editor/examples/user-menu/editor.tsx deleted file mode 100644 index 30fee3d379..0000000000 --- a/solid-user-menu/src/components/editor/examples/user-menu/editor.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { tags } from '../../sample/sample-tag-data' -import { users } from '../../sample/sample-user-data' -import { TagMenu } from '../../ui/tag-menu' -import { UserMenu } from '../../ui/user-menu' - -import { defineExtension } from './extension' - -export default function Editor(): JSX.Element { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return ( - -
-
-
- - -
-
-
- ) -} diff --git a/solid-user-menu/src/components/editor/examples/user-menu/extension.ts b/solid-user-menu/src/components/editor/examples/user-menu/extension.ts deleted file mode 100644 index 56a97a4779..0000000000 --- a/solid-user-menu/src/components/editor/examples/user-menu/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone or # to tag something...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-user-menu/src/components/editor/examples/user-menu/index.ts b/solid-user-menu/src/components/editor/examples/user-menu/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-user-menu/src/components/editor/examples/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-user-menu/src/components/editor/sample/sample-tag-data.ts b/solid-user-menu/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/solid-user-menu/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/solid-user-menu/src/components/editor/sample/sample-user-data.ts b/solid-user-menu/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/solid-user-menu/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/solid-user-menu/src/components/editor/ui/tag-menu/index.ts b/solid-user-menu/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index d344b33a70..0000000000 --- a/solid-user-menu/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu' diff --git a/solid-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx b/solid-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx deleted file mode 100644 index 03e3534da3..0000000000 --- a/solid-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/solid' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/solid/autocomplete' -import { For, type JSX } from 'solid-js' - -const regex = /#[\da-z]*$/i - -export default function TagMenu(props: { - tags: { id: number; label: string }[] -}): JSX.Element { - const editor = useEditor>() - - const handleTagInsert = (id: number, label: string) => { - editor().commands.insertMention({ - id: id.toString(), - value: '#' + label, - kind: 'tag', - }) - editor().commands.insertText({ text: ' ' }) - } - - return ( - - - -
- - No results - - - - {(tag) => ( - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - )} - -
-
-
-
- ) -} diff --git a/solid-user-menu/src/components/editor/ui/user-menu/index.ts b/solid-user-menu/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index f30e75d5da..0000000000 --- a/solid-user-menu/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu' diff --git a/solid-user-menu/src/components/editor/ui/user-menu/user-menu.tsx b/solid-user-menu/src/components/editor/ui/user-menu/user-menu.tsx deleted file mode 100644 index 61d3cd96d8..0000000000 --- a/solid-user-menu/src/components/editor/ui/user-menu/user-menu.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import { canUseRegexLookbehind, type Union } from 'prosekit/core' -import type { MentionExtension } from 'prosekit/extensions/mention' -import { useEditor } from 'prosekit/solid' -import { - AutocompleteEmpty, - AutocompleteItem, - AutocompletePopup, - AutocompletePositioner, - AutocompleteRoot, -} from 'prosekit/solid/autocomplete' -import { For, type JSX } from 'solid-js' - -// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". -const regex = canUseRegexLookbehind() ? /(? void - onOpenChange?: (open: boolean) => void -}): JSX.Element { - const editor = useEditor>() - - const handleUserInsert = (id: number, username: string) => { - editor().commands.insertMention({ - id: id.toString(), - value: '@' + username, - kind: 'user', - }) - editor().commands.insertText({ text: ' ' }) - } - - return ( - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} - > - - -
- - {props.loading ? 'Loading...' : 'No results'} - - - - {(user) => ( - handleUserInsert(user.id, user.name)} - > - - {user.name} - - - )} - -
-
-
-
- ) -} diff --git a/solid-user-menu/src/index.tsx b/solid-user-menu/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-user-menu/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-user-menu/tsconfig.app.json b/solid-user-menu/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-user-menu/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-user-menu/tsconfig.json b/solid-user-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-user-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-user-menu/tsconfig.node.json b/solid-user-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-user-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-user-menu/vite.config.ts b/solid-user-menu/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-user-menu/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-word-counter/.gitignore b/solid-word-counter/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-word-counter/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-word-counter/README.md b/solid-word-counter/README.md deleted file mode 100644 index d7f1e4743f..0000000000 --- a/solid-word-counter/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-word-counter - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-word-counter) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-word-counter) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-word-counter solid-word-counter -cd solid-word-counter -npm install -npm run dev -``` diff --git a/solid-word-counter/index.html b/solid-word-counter/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-word-counter/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-word-counter/package.json b/solid-word-counter/package.json deleted file mode 100644 index 48f953f7e6..0000000000 --- a/solid-word-counter/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "example-solid-word-counter", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-word-counter/src/App.tsx b/solid-word-counter/src/App.tsx deleted file mode 100644 index 9da98dddb5..0000000000 --- a/solid-word-counter/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/word-counter' - -export default function App() { - return -} diff --git a/solid-word-counter/src/app.css b/solid-word-counter/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-word-counter/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-word-counter/src/components/editor/examples/word-counter/editor.tsx b/solid-word-counter/src/components/editor/examples/word-counter/editor.tsx deleted file mode 100644 index 84b8e69273..0000000000 --- a/solid-word-counter/src/components/editor/examples/word-counter/editor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor, type NodeJSON } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -import { sampleContent } from '../../sample/sample-doc-word-counter' -import { WordCounter } from '../../ui/word-counter' - -import { defineExtension } from './extension' - -interface EditorProps { - initialContent?: NodeJSON -} - -export default function Editor(props: EditorProps): JSX.Element { - const defaultContent = props.initialContent ?? sampleContent - const extension = defineExtension() - const editor = createEditor({ extension, defaultContent }) - - return ( - -
-
-
- -
-
-
- ) -} diff --git a/solid-word-counter/src/components/editor/examples/word-counter/extension.ts b/solid-word-counter/src/components/editor/examples/word-counter/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/solid-word-counter/src/components/editor/examples/word-counter/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/solid-word-counter/src/components/editor/examples/word-counter/index.ts b/solid-word-counter/src/components/editor/examples/word-counter/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-word-counter/src/components/editor/examples/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/solid-word-counter/src/components/editor/sample/sample-doc-word-counter.ts deleted file mode 100644 index 0b5d435038..0000000000 --- a/solid-word-counter/src/components/editor/sample/sample-doc-word-counter.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Start typing and observe the word count update below.', - }, - ], - }, - ], -} diff --git a/solid-word-counter/src/components/editor/ui/word-counter/index.ts b/solid-word-counter/src/components/editor/ui/word-counter/index.ts deleted file mode 100644 index 929ee3e41a..0000000000 --- a/solid-word-counter/src/components/editor/ui/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as WordCounter } from './word-counter' diff --git a/solid-word-counter/src/components/editor/ui/word-counter/word-counter.tsx b/solid-word-counter/src/components/editor/ui/word-counter/word-counter.tsx deleted file mode 100644 index bb527a1897..0000000000 --- a/solid-word-counter/src/components/editor/ui/word-counter/word-counter.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import type { Editor } from 'prosekit/core' -import { useEditorDerivedValue } from 'prosekit/solid' -import type { JSX } from 'solid-js' - -function getWordCount(editor: Editor) { - const doc = editor.state.doc - const words = doc ? doc.textBetween(0, doc.content.size, ' ') : '' - const wordCount = words.split(/\s+/).filter((s) => s).length - const characterCount = doc ? doc.textContent.length : 0 - return { wordCount, characterCount } -} - -export default function WordCounter(): JSX.Element { - const counts = useEditorDerivedValue(getWordCount) - - return ( -
- Word Count: {counts().wordCount} -
- Character Count: {counts().characterCount} -
- ) -} diff --git a/solid-word-counter/src/index.tsx b/solid-word-counter/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-word-counter/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-word-counter/tsconfig.app.json b/solid-word-counter/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-word-counter/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-word-counter/tsconfig.json b/solid-word-counter/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-word-counter/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-word-counter/tsconfig.node.json b/solid-word-counter/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-word-counter/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-word-counter/vite.config.ts b/solid-word-counter/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-word-counter/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/solid-yjs/.gitignore b/solid-yjs/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/solid-yjs/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/solid-yjs/README.md b/solid-yjs/README.md deleted file mode 100644 index 7277cc063f..0000000000 --- a/solid-yjs/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# solid-yjs - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-yjs) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-yjs) - -Run the example locally with: - -```bash -npx degit prosekit/examples/solid-yjs solid-yjs -cd solid-yjs -npm install -npm run dev -``` diff --git a/solid-yjs/index.html b/solid-yjs/index.html deleted file mode 100644 index 375ea8dbc4..0000000000 --- a/solid-yjs/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Solid - - -
- - - diff --git a/solid-yjs/package.json b/solid-yjs/package.json deleted file mode 100644 index aa882ebad8..0000000000 --- a/solid-yjs/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-solid-yjs", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "solid-js": "^1.9.13", - "y-prosemirror": "^1.3.7", - "y-protocols": "^1.0.7", - "y-websocket": "^3.0.0", - "yjs": "^13.6.30" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-solid": "^2.11.12" - } -} diff --git a/solid-yjs/src/App.tsx b/solid-yjs/src/App.tsx deleted file mode 100644 index 8641aefe47..0000000000 --- a/solid-yjs/src/App.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ExampleEditor } from './components/editor/examples/yjs' - -export default function App() { - return -} diff --git a/solid-yjs/src/app.css b/solid-yjs/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/solid-yjs/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/solid-yjs/src/components/editor/examples/yjs/editor-component.tsx b/solid-yjs/src/components/editor/examples/yjs/editor-component.tsx deleted file mode 100644 index 6661dac8c8..0000000000 --- a/solid-yjs/src/components/editor/examples/yjs/editor-component.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' -import 'prosekit/extensions/yjs/style.css' - -import { createEditor } from 'prosekit/core' -import { ProseKit } from 'prosekit/solid' -import { createMemo, type JSX } from 'solid-js' -import { WebsocketProvider } from 'y-websocket' -import * as Y from 'yjs' - -import { Toolbar } from '../../ui/toolbar' - -import { defineExtension } from './extension' - -export default function EditorComponent(props: { room?: string }): JSX.Element { - const editor = createMemo(() => { - const doc = new Y.Doc() - const provider = new WebsocketProvider( - 'wss://demos.yjs.dev/ws', - `github.com/prosekit/room_${props.room}`, - doc, - ) - - const extension = defineExtension(doc, provider.awareness) - return createEditor({ extension }) - }) - - return ( - -
- -
-
-
-
-
- ) -} diff --git a/solid-yjs/src/components/editor/examples/yjs/editor.tsx b/solid-yjs/src/components/editor/examples/yjs/editor.tsx deleted file mode 100644 index a047471e66..0000000000 --- a/solid-yjs/src/components/editor/examples/yjs/editor.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { createSignal, type JSX } from 'solid-js' - -import EditorComponent from './editor-component' - -export default function Editor(): JSX.Element { - const [room] = createSignal(Math.random().toString(36).substring(2, 15)) - - return ( -
- - -
- ) -} diff --git a/solid-yjs/src/components/editor/examples/yjs/extension.ts b/solid-yjs/src/components/editor/examples/yjs/extension.ts deleted file mode 100644 index b2546b126e..0000000000 --- a/solid-yjs/src/components/editor/examples/yjs/extension.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' -import { defineYjs } from 'prosekit/extensions/yjs' -import type { Awareness } from 'prosekit/extensions/yjs' -import type * as Y from 'yjs' - -export function defineExtension(doc: Y.Doc, awareness: Awareness) { - return union( - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineYjs({ doc, awareness }), - ) -} - -export type EditorExtension = ReturnType diff --git a/solid-yjs/src/components/editor/examples/yjs/index.ts b/solid-yjs/src/components/editor/examples/yjs/index.ts deleted file mode 100644 index 1a07a6017a..0000000000 --- a/solid-yjs/src/components/editor/examples/yjs/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor' diff --git a/solid-yjs/src/components/editor/ui/button/button.tsx b/solid-yjs/src/components/editor/ui/button/button.tsx deleted file mode 100644 index a1b2e44b0c..0000000000 --- a/solid-yjs/src/components/editor/ui/button/button.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { - TooltipPopup, - TooltipPositioner, - TooltipRoot, - TooltipTrigger, -} from 'prosekit/solid/tooltip' -import type { JSX } from 'solid-js' - -export default function Button(props: { - pressed?: boolean - disabled?: boolean - onClick?: () => void - tooltip?: string - children: JSX.Element -}): JSX.Element { - return ( - - - - - {props.tooltip ? ( - - - {props.tooltip} - - - ) : null} - - ) -} diff --git a/solid-yjs/src/components/editor/ui/button/index.ts b/solid-yjs/src/components/editor/ui/button/index.ts deleted file mode 100644 index 9743944eda..0000000000 --- a/solid-yjs/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button' diff --git a/solid-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx deleted file mode 100644 index efa306305f..0000000000 --- a/solid-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' -import type { ImageExtension } from 'prosekit/extensions/image' -import { useEditor } from 'prosekit/solid' -import { - PopoverPopup, - PopoverPositioner, - PopoverRoot, - PopoverTrigger, -} from 'prosekit/solid/popover' -import type { OpenChangeEvent } from 'prosekit/web/popover' -import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' - -import { Button } from '../button' - -export default function ImageUploadPopover(props: { - uploader: Uploader - tooltip: string - disabled: boolean - children: JSX.Element -}): JSX.Element { - const [open, setOpen] = createSignal(false) - const [url, setUrl] = createSignal('') - const [file, setFile] = createSignal(null) - const ariaId = createUniqueId() - - const editor = useEditor() - - const handleFileChange = (event: Event) => { - const target = event.target as HTMLInputElement - const selectedFile = target.files?.[0] - - if (selectedFile) { - setFile(selectedFile) - setUrl('') - } else { - setFile(null) - } - } - - const handleUrlChange = (event: Event) => { - const target = event.target as HTMLInputElement - const inputUrl = target.value - - if (inputUrl) { - setUrl(inputUrl) - setFile(null) - } else { - setUrl('') - } - } - - const deferResetState = () => { - setTimeout(() => { - setUrl('') - setFile(null) - }, 300) - } - - const handleSubmit = () => { - if (url()) { - editor().commands.insertImage({ src: url() }) - } else if (file()) { - editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) - } - setOpen(false) - deferResetState() - } - - const handleOpenChange = (event: OpenChangeEvent) => { - if (!event.detail) { - deferResetState() - } - setOpen(event.detail) - } - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} diff --git a/solid-yjs/src/components/editor/ui/image-upload-popover/index.ts b/solid-yjs/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index 5d49d873ce..0000000000 --- a/solid-yjs/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-yjs/src/components/editor/ui/toolbar/index.ts b/solid-yjs/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index fdf6741e6a..0000000000 --- a/solid-yjs/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar' diff --git a/solid-yjs/src/components/editor/ui/toolbar/toolbar.tsx b/solid-yjs/src/components/editor/ui/toolbar/toolbar.tsx deleted file mode 100644 index ee3858791a..0000000000 --- a/solid-yjs/src/components/editor/ui/toolbar/toolbar.tsx +++ /dev/null @@ -1,406 +0,0 @@ -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import type { Uploader } from 'prosekit/extensions/file' -import { useEditorDerivedValue } from 'prosekit/solid' -import { Show, type JSX } from 'solid-js' - -import { Button } from '../button' -import { ImageUploadPopover } from '../image-upload-popover' - -function getToolbarItems(editor: Editor) { - return { - undo: editor.commands.undo - ? { - isActive: false, - canExec: editor.commands.undo.canExec(), - command: () => editor.commands.undo(), - } - : undefined, - redo: editor.commands.redo - ? { - isActive: false, - canExec: editor.commands.redo.canExec(), - command: () => editor.commands.redo(), - } - : undefined, - bold: editor.commands.toggleBold - ? { - isActive: editor.marks.bold.isActive(), - canExec: editor.commands.toggleBold.canExec(), - command: () => editor.commands.toggleBold(), - } - : undefined, - italic: editor.commands.toggleItalic - ? { - isActive: editor.marks.italic.isActive(), - canExec: editor.commands.toggleItalic.canExec(), - command: () => editor.commands.toggleItalic(), - } - : undefined, - underline: editor.commands.toggleUnderline - ? { - isActive: editor.marks.underline.isActive(), - canExec: editor.commands.toggleUnderline.canExec(), - command: () => editor.commands.toggleUnderline(), - } - : undefined, - strike: editor.commands.toggleStrike - ? { - isActive: editor.marks.strike.isActive(), - canExec: editor.commands.toggleStrike.canExec(), - command: () => editor.commands.toggleStrike(), - } - : undefined, - code: editor.commands.toggleCode - ? { - isActive: editor.marks.code.isActive(), - canExec: editor.commands.toggleCode.canExec(), - command: () => editor.commands.toggleCode(), - } - : undefined, - codeBlock: editor.commands.insertCodeBlock - ? { - isActive: editor.nodes.codeBlock.isActive(), - canExec: editor.commands.insertCodeBlock.canExec({ - language: 'javascript', - }), - command: () => - editor.commands.insertCodeBlock({ language: 'javascript' }), - } - : undefined, - heading1: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 1 }), - canExec: editor.commands.toggleHeading.canExec({ level: 1 }), - command: () => editor.commands.toggleHeading({ level: 1 }), - } - : undefined, - heading2: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 2 }), - canExec: editor.commands.toggleHeading.canExec({ level: 2 }), - command: () => editor.commands.toggleHeading({ level: 2 }), - } - : undefined, - heading3: editor.commands.toggleHeading - ? { - isActive: editor.nodes.heading.isActive({ level: 3 }), - canExec: editor.commands.toggleHeading.canExec({ level: 3 }), - command: () => editor.commands.toggleHeading({ level: 3 }), - } - : undefined, - horizontalRule: editor.commands.insertHorizontalRule - ? { - isActive: editor.nodes.horizontalRule.isActive(), - canExec: editor.commands.insertHorizontalRule.canExec(), - command: () => editor.commands.insertHorizontalRule(), - } - : undefined, - blockquote: editor.commands.toggleBlockquote - ? { - isActive: editor.nodes.blockquote.isActive(), - canExec: editor.commands.toggleBlockquote.canExec(), - command: () => editor.commands.toggleBlockquote(), - } - : undefined, - bulletList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'bullet' }), - canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), - command: () => editor.commands.toggleList({ kind: 'bullet' }), - } - : undefined, - orderedList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'ordered' }), - canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), - command: () => editor.commands.toggleList({ kind: 'ordered' }), - } - : undefined, - taskList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'task' }), - canExec: editor.commands.toggleList.canExec({ kind: 'task' }), - command: () => editor.commands.toggleList({ kind: 'task' }), - } - : undefined, - toggleList: editor.commands.toggleList - ? { - isActive: editor.nodes.list.isActive({ kind: 'toggle' }), - canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), - command: () => editor.commands.toggleList({ kind: 'toggle' }), - } - : undefined, - indentList: editor.commands.indentList - ? { - isActive: false, - canExec: editor.commands.indentList.canExec(), - command: () => editor.commands.indentList(), - } - : undefined, - dedentList: editor.commands.dedentList - ? { - isActive: false, - canExec: editor.commands.dedentList.canExec(), - command: () => editor.commands.dedentList(), - } - : undefined, - insertImage: editor.commands.insertImage - ? { - isActive: false, - canExec: editor.commands.insertImage.canExec(), - } - : undefined, - } -} - -export default function Toolbar(props: { - uploader?: Uploader -}): JSX.Element { - const items = useEditorDerivedValue(getToolbarItems) - - return ( -
- - {(item) => ( - - )} - - - {(item) => ( - - )} - - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - - )} - - - {(item) => ( - -
- - )} - -
- ) -} diff --git a/solid-yjs/src/index.tsx b/solid-yjs/src/index.tsx deleted file mode 100644 index 92b7740757..0000000000 --- a/solid-yjs/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/* @refresh reload */ -import './app.css' -import { render } from 'solid-js/web' -import App from './App' - -const root = document.getElementById('root') - -render(() => , root!) diff --git a/solid-yjs/tsconfig.app.json b/solid-yjs/tsconfig.app.json deleted file mode 100644 index c0b480e758..0000000000 --- a/solid-yjs/tsconfig.app.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - "jsx": "preserve", - "jsxImportSource": "solid-js", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/solid-yjs/tsconfig.json b/solid-yjs/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/solid-yjs/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/solid-yjs/tsconfig.node.json b/solid-yjs/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/solid-yjs/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/solid-yjs/vite.config.ts b/solid-yjs/vite.config.ts deleted file mode 100644 index 9cb3cb51fd..0000000000 --- a/solid-yjs/vite.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vite' -import solid from 'vite-plugin-solid' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [solid(), tailwindcss()], -}) diff --git a/svelte-block-handle/.gitignore b/svelte-block-handle/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-block-handle/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-block-handle/README.md b/svelte-block-handle/README.md deleted file mode 100644 index dcf3b1238c..0000000000 --- a/svelte-block-handle/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-block-handle - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-block-handle) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-block-handle) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-block-handle svelte-block-handle -cd svelte-block-handle -npm install -npm run dev -``` diff --git a/svelte-block-handle/index.html b/svelte-block-handle/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-block-handle/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-block-handle/package.json b/svelte-block-handle/package.json deleted file mode 100644 index e3cadcf8a1..0000000000 --- a/svelte-block-handle/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-block-handle", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-block-handle/src/App.svelte b/svelte-block-handle/src/App.svelte deleted file mode 100644 index 3d9f1706f0..0000000000 --- a/svelte-block-handle/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-block-handle/src/app.css b/svelte-block-handle/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-block-handle/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-block-handle/src/components/editor/examples/block-handle/editor.svelte b/svelte-block-handle/src/components/editor/examples/block-handle/editor.svelte deleted file mode 100644 index 4d5fa066df..0000000000 --- a/svelte-block-handle/src/components/editor/examples/block-handle/editor.svelte +++ /dev/null @@ -1,32 +0,0 @@ - - - -
-
-
- - -
-
-
diff --git a/svelte-block-handle/src/components/editor/examples/block-handle/extension.ts b/svelte-block-handle/src/components/editor/examples/block-handle/extension.ts deleted file mode 100644 index b5686b8c04..0000000000 --- a/svelte-block-handle/src/components/editor/examples/block-handle/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union(defineBasicExtension(), defineCodeBlockView()) -} - -export type EditorExtension = ReturnType diff --git a/svelte-block-handle/src/components/editor/examples/block-handle/index.ts b/svelte-block-handle/src/components/editor/examples/block-handle/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-block-handle/src/components/editor/examples/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/svelte-block-handle/src/components/editor/sample/sample-doc-block-handle.ts deleted file mode 100644 index 3c6ccdc203..0000000000 --- a/svelte-block-handle/src/components/editor/sample/sample-doc-block-handle.ts +++ /dev/null @@ -1,323 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Drag and Drop Demo', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Getting Started', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This paragraph can be moved above or below other blocks.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Different Block Types', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'You can drag paragraphs, headings, lists, code blocks, and more.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Lists Work Too', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This entire list can be dragged', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Individual list items stay together', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try moving this list around', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Ordered lists also support dragging', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The numbering updates automatically', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag this list to see it in action', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Even code blocks can be moved:', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: 'javascript', - }, - content: [ - { - type: 'text', - text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Nested Content', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This blockquote can be moved as a single unit.', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested blockquotes move together with their parent.', - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Try It Yourself', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Practice by moving this paragraph to the top of the document.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Or drag this one to between the headings above.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The drag handles make it easy to reorganize your content exactly how you want it.', - }, - ], - }, - ], -} diff --git a/svelte-block-handle/src/components/editor/ui/block-handle/block-handle.svelte b/svelte-block-handle/src/components/editor/ui/block-handle/block-handle.svelte deleted file mode 100644 index f67e42dc91..0000000000 --- a/svelte-block-handle/src/components/editor/ui/block-handle/block-handle.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - -
-
- -
-
-
-
-
diff --git a/svelte-block-handle/src/components/editor/ui/block-handle/index.ts b/svelte-block-handle/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 6d21191384..0000000000 --- a/svelte-block-handle/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.svelte' diff --git a/svelte-block-handle/src/components/editor/ui/code-block-view/code-block-view.svelte b/svelte-block-handle/src/components/editor/ui/code-block-view/code-block-view.svelte deleted file mode 100644 index aaa4617fc1..0000000000 --- a/svelte-block-handle/src/components/editor/ui/code-block-view/code-block-view.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - -

diff --git a/svelte-block-handle/src/components/editor/ui/code-block-view/index.ts b/svelte-block-handle/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index eb54b2f6d9..0000000000
--- a/svelte-block-handle/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSvelteNodeView,
-  type SvelteNodeViewComponent,
-} from 'prosekit/svelte'
-
-import CodeBlockView from './code-block-view.svelte'
-
-export function defineCodeBlockView(): Extension {
-  return defineSvelteNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView as SvelteNodeViewComponent,
-  })
-}
diff --git a/svelte-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/svelte-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.svelte
deleted file mode 100644
index 7f6cac1db0..0000000000
--- a/svelte-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.svelte
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/svelte-block-handle/src/components/editor/ui/drop-indicator/index.ts b/svelte-block-handle/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index 06e89357ed..0000000000
--- a/svelte-block-handle/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator.svelte'
diff --git a/svelte-block-handle/src/main.ts b/svelte-block-handle/src/main.ts
deleted file mode 100644
index b4bc565380..0000000000
--- a/svelte-block-handle/src/main.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import './app.css'
-
-import { mount } from 'svelte'
-import App from './App.svelte'
-
-const app = mount(App, { target: document.getElementById('app')! })
-
-export default app
diff --git a/svelte-block-handle/src/vite-env.d.ts b/svelte-block-handle/src/vite-env.d.ts
deleted file mode 100644
index 4078e7476a..0000000000
--- a/svelte-block-handle/src/vite-env.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-/// 
-/// 
diff --git a/svelte-block-handle/svelte.config.js b/svelte-block-handle/svelte.config.js
deleted file mode 100644
index b0683fd24d..0000000000
--- a/svelte-block-handle/svelte.config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
-
-export default {
-  // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
-  // for more information about preprocessors
-  preprocess: vitePreprocess(),
-}
diff --git a/svelte-block-handle/tsconfig.json b/svelte-block-handle/tsconfig.json
deleted file mode 100644
index 86876593dd..0000000000
--- a/svelte-block-handle/tsconfig.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "extends": "@tsconfig/svelte/tsconfig.json",
-  "compilerOptions": {
-    "target": "ESNext",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "resolveJsonModule": true,
-    /**
-     * Typecheck JS in `.svelte` and `.js` files by default.
-     * Disable checkJs if you'd like to use dynamic types in JS.
-     * Note that setting allowJs false does not prevent the use
-     * of JS in `.svelte` files.
-     */
-    "allowJs": true,
-    "checkJs": true,
-    "allowImportingTsExtensions": true,
-    "isolatedModules": true
-  },
-  "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
-  "references": [{ "path": "./tsconfig.node.json" }]
-}
diff --git a/svelte-block-handle/tsconfig.node.json b/svelte-block-handle/tsconfig.node.json
deleted file mode 100644
index 494bfe0835..0000000000
--- a/svelte-block-handle/tsconfig.node.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "compilerOptions": {
-    "composite": true,
-    "skipLibCheck": true,
-    "module": "ESNext",
-    "moduleResolution": "bundler"
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/svelte-block-handle/vite.config.ts b/svelte-block-handle/vite.config.ts
deleted file mode 100644
index 11edea7f23..0000000000
--- a/svelte-block-handle/vite.config.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { defineConfig } from 'vite'
-import { svelte } from '@sveltejs/vite-plugin-svelte'
-import tailwindcss from '@tailwindcss/vite'
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  plugins: [svelte(), tailwindcss()],
-})
diff --git a/svelte-blockquote/.gitignore b/svelte-blockquote/.gitignore
deleted file mode 100644
index 5d6225c6df..0000000000
--- a/svelte-blockquote/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-dist
-.next
-.svelte-kit
diff --git a/svelte-blockquote/README.md b/svelte-blockquote/README.md
deleted file mode 100644
index 06c1bd959c..0000000000
--- a/svelte-blockquote/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# svelte-blockquote
-
-A [ProseKit](https://prosekit.dev) example.
-
-[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-blockquote)
-[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-blockquote)
-
-Run the example locally with:
-
-```bash
-npx degit prosekit/examples/svelte-blockquote svelte-blockquote
-cd svelte-blockquote
-npm install
-npm run dev
-```
diff --git a/svelte-blockquote/index.html b/svelte-blockquote/index.html
deleted file mode 100644
index 58212c2501..0000000000
--- a/svelte-blockquote/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-  
-    
-    
-    ProseKit + Svelte
-  
-  
-    
- - - diff --git a/svelte-blockquote/package.json b/svelte-blockquote/package.json deleted file mode 100644 index aca51e3efd..0000000000 --- a/svelte-blockquote/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-blockquote", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-blockquote/src/App.svelte b/svelte-blockquote/src/App.svelte deleted file mode 100644 index 29b9c5ff97..0000000000 --- a/svelte-blockquote/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-blockquote/src/app.css b/svelte-blockquote/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-blockquote/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-blockquote/src/components/editor/examples/blockquote/editor.svelte b/svelte-blockquote/src/components/editor/examples/blockquote/editor.svelte deleted file mode 100644 index 741b836c3c..0000000000 --- a/svelte-blockquote/src/components/editor/examples/blockquote/editor.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-blockquote/src/components/editor/examples/blockquote/extension.ts b/svelte-blockquote/src/components/editor/examples/blockquote/extension.ts deleted file mode 100644 index 5292b59e35..0000000000 --- a/svelte-blockquote/src/components/editor/examples/blockquote/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBlockquote(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-blockquote/src/components/editor/examples/blockquote/index.ts b/svelte-blockquote/src/components/editor/examples/blockquote/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-blockquote/src/components/editor/examples/blockquote/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-blockquote/src/components/editor/ui/button/button.svelte b/svelte-blockquote/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-blockquote/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-blockquote/src/components/editor/ui/button/index.ts b/svelte-blockquote/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-blockquote/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/svelte-blockquote/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-blockquote/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-blockquote/src/components/editor/ui/toolbar/index.ts b/svelte-blockquote/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-blockquote/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-blockquote/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-blockquote/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-blockquote/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-blockquote/src/main.ts b/svelte-blockquote/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-blockquote/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-blockquote/src/vite-env.d.ts b/svelte-blockquote/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-blockquote/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-blockquote/svelte.config.js b/svelte-blockquote/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-blockquote/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-blockquote/tsconfig.json b/svelte-blockquote/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-blockquote/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-blockquote/tsconfig.node.json b/svelte-blockquote/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-blockquote/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-blockquote/vite.config.ts b/svelte-blockquote/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-blockquote/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-bold/.gitignore b/svelte-bold/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-bold/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-bold/README.md b/svelte-bold/README.md deleted file mode 100644 index d8c4f03064..0000000000 --- a/svelte-bold/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-bold - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-bold) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-bold) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-bold svelte-bold -cd svelte-bold -npm install -npm run dev -``` diff --git a/svelte-bold/index.html b/svelte-bold/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-bold/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-bold/package.json b/svelte-bold/package.json deleted file mode 100644 index 7dff1a5f3f..0000000000 --- a/svelte-bold/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-bold", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-bold/src/App.svelte b/svelte-bold/src/App.svelte deleted file mode 100644 index 222bcdb5f6..0000000000 --- a/svelte-bold/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-bold/src/app.css b/svelte-bold/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-bold/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-bold/src/components/editor/examples/bold/editor.svelte b/svelte-bold/src/components/editor/examples/bold/editor.svelte deleted file mode 100644 index e0601d8915..0000000000 --- a/svelte-bold/src/components/editor/examples/bold/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-bold/src/components/editor/examples/bold/extension.ts b/svelte-bold/src/components/editor/examples/bold/extension.ts deleted file mode 100644 index eaa4fba721..0000000000 --- a/svelte-bold/src/components/editor/examples/bold/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBold } from 'prosekit/extensions/bold' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBold(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-bold/src/components/editor/examples/bold/index.ts b/svelte-bold/src/components/editor/examples/bold/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-bold/src/components/editor/examples/bold/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-bold/src/components/editor/sample/sample-doc-bold.ts b/svelte-bold/src/components/editor/sample/sample-doc-bold.ts deleted file mode 100644 index 09ed08daad..0000000000 --- a/svelte-bold/src/components/editor/sample/sample-doc-bold.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/svelte-bold/src/components/editor/ui/button/button.svelte b/svelte-bold/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-bold/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-bold/src/components/editor/ui/button/index.ts b/svelte-bold/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-bold/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-bold/src/components/editor/ui/image-upload-popover/index.ts b/svelte-bold/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-bold/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-bold/src/components/editor/ui/toolbar/index.ts b/svelte-bold/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-bold/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-bold/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-bold/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-bold/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-bold/src/main.ts b/svelte-bold/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-bold/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-bold/src/vite-env.d.ts b/svelte-bold/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-bold/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-bold/svelte.config.js b/svelte-bold/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-bold/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-bold/tsconfig.json b/svelte-bold/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-bold/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-bold/tsconfig.node.json b/svelte-bold/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-bold/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-bold/vite.config.ts b/svelte-bold/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-bold/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-change-tracking/.gitignore b/svelte-change-tracking/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-change-tracking/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-change-tracking/README.md b/svelte-change-tracking/README.md deleted file mode 100644 index 38c01b55c9..0000000000 --- a/svelte-change-tracking/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-change-tracking - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-change-tracking) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-change-tracking) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-change-tracking svelte-change-tracking -cd svelte-change-tracking -npm install -npm run dev -``` diff --git a/svelte-change-tracking/index.html b/svelte-change-tracking/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-change-tracking/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-change-tracking/package.json b/svelte-change-tracking/package.json deleted file mode 100644 index 3649a10146..0000000000 --- a/svelte-change-tracking/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-change-tracking", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-change-tracking/src/App.svelte b/svelte-change-tracking/src/App.svelte deleted file mode 100644 index ea0c2b2b45..0000000000 --- a/svelte-change-tracking/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-change-tracking/src/app.css b/svelte-change-tracking/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-change-tracking/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-diff.svelte b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-diff.svelte deleted file mode 100644 index b8871f656f..0000000000 --- a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-diff.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-main.svelte b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-main.svelte deleted file mode 100644 index a46ea48604..0000000000 --- a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-main.svelte +++ /dev/null @@ -1,34 +0,0 @@ - - -{#key props.key} - -
-
-
-
-
-
-{/key} diff --git a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor.svelte b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor.svelte deleted file mode 100644 index 8e74f7510a..0000000000 --- a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor.svelte +++ /dev/null @@ -1,63 +0,0 @@ - - -
-
-
- -
- -
-
- {#each commits as commit (commit.id)} -
-
- -
-
- - {commit.date.toLocaleTimeString()} - - -
-
- {/each} -
-
diff --git a/svelte-change-tracking/src/components/editor/examples/change-tracking/index.ts b/svelte-change-tracking/src/components/editor/examples/change-tracking/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-change-tracking/src/components/editor/examples/change-tracking/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-change-tracking/src/main.ts b/svelte-change-tracking/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-change-tracking/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-change-tracking/src/vite-env.d.ts b/svelte-change-tracking/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-change-tracking/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-change-tracking/svelte.config.js b/svelte-change-tracking/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-change-tracking/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-change-tracking/tsconfig.json b/svelte-change-tracking/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-change-tracking/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-change-tracking/tsconfig.node.json b/svelte-change-tracking/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-change-tracking/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-change-tracking/vite.config.ts b/svelte-change-tracking/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-change-tracking/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-code-block-themes/.gitignore b/svelte-code-block-themes/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-code-block-themes/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-code-block-themes/README.md b/svelte-code-block-themes/README.md deleted file mode 100644 index e35ce06d8a..0000000000 --- a/svelte-code-block-themes/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-code-block-themes - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-code-block-themes) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-code-block-themes) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-code-block-themes svelte-code-block-themes -cd svelte-code-block-themes -npm install -npm run dev -``` diff --git a/svelte-code-block-themes/index.html b/svelte-code-block-themes/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-code-block-themes/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-code-block-themes/package.json b/svelte-code-block-themes/package.json deleted file mode 100644 index f4fd35ba41..0000000000 --- a/svelte-code-block-themes/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-code-block-themes", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-code-block-themes/src/App.svelte b/svelte-code-block-themes/src/App.svelte deleted file mode 100644 index 25547b27a9..0000000000 --- a/svelte-code-block-themes/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-code-block-themes/src/app.css b/svelte-code-block-themes/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-code-block-themes/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/editor.svelte b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/editor.svelte deleted file mode 100644 index 4a259bc074..0000000000 --- a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts deleted file mode 100644 index b5686b8c04..0000000000 --- a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union(defineBasicExtension(), defineCodeBlockView()) -} - -export type EditorExtension = ReturnType diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.svelte b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.svelte deleted file mode 100644 index c62d761fc2..0000000000 --- a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - - - diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.svelte b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.svelte deleted file mode 100644 index a585851af0..0000000000 --- a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - -
- -
diff --git a/svelte-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/svelte-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/svelte-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/svelte-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.svelte b/svelte-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.svelte deleted file mode 100644 index aaa4617fc1..0000000000 --- a/svelte-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - -

diff --git a/svelte-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/svelte-code-block-themes/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index eb54b2f6d9..0000000000
--- a/svelte-code-block-themes/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSvelteNodeView,
-  type SvelteNodeViewComponent,
-} from 'prosekit/svelte'
-
-import CodeBlockView from './code-block-view.svelte'
-
-export function defineCodeBlockView(): Extension {
-  return defineSvelteNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView as SvelteNodeViewComponent,
-  })
-}
diff --git a/svelte-code-block-themes/src/main.ts b/svelte-code-block-themes/src/main.ts
deleted file mode 100644
index b4bc565380..0000000000
--- a/svelte-code-block-themes/src/main.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import './app.css'
-
-import { mount } from 'svelte'
-import App from './App.svelte'
-
-const app = mount(App, { target: document.getElementById('app')! })
-
-export default app
diff --git a/svelte-code-block-themes/src/vite-env.d.ts b/svelte-code-block-themes/src/vite-env.d.ts
deleted file mode 100644
index 4078e7476a..0000000000
--- a/svelte-code-block-themes/src/vite-env.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-/// 
-/// 
diff --git a/svelte-code-block-themes/svelte.config.js b/svelte-code-block-themes/svelte.config.js
deleted file mode 100644
index b0683fd24d..0000000000
--- a/svelte-code-block-themes/svelte.config.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
-
-export default {
-  // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
-  // for more information about preprocessors
-  preprocess: vitePreprocess(),
-}
diff --git a/svelte-code-block-themes/tsconfig.json b/svelte-code-block-themes/tsconfig.json
deleted file mode 100644
index 86876593dd..0000000000
--- a/svelte-code-block-themes/tsconfig.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-  "extends": "@tsconfig/svelte/tsconfig.json",
-  "compilerOptions": {
-    "target": "ESNext",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "resolveJsonModule": true,
-    /**
-     * Typecheck JS in `.svelte` and `.js` files by default.
-     * Disable checkJs if you'd like to use dynamic types in JS.
-     * Note that setting allowJs false does not prevent the use
-     * of JS in `.svelte` files.
-     */
-    "allowJs": true,
-    "checkJs": true,
-    "allowImportingTsExtensions": true,
-    "isolatedModules": true
-  },
-  "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
-  "references": [{ "path": "./tsconfig.node.json" }]
-}
diff --git a/svelte-code-block-themes/tsconfig.node.json b/svelte-code-block-themes/tsconfig.node.json
deleted file mode 100644
index 494bfe0835..0000000000
--- a/svelte-code-block-themes/tsconfig.node.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "compilerOptions": {
-    "composite": true,
-    "skipLibCheck": true,
-    "module": "ESNext",
-    "moduleResolution": "bundler"
-  },
-  "include": ["vite.config.ts"]
-}
diff --git a/svelte-code-block-themes/vite.config.ts b/svelte-code-block-themes/vite.config.ts
deleted file mode 100644
index 11edea7f23..0000000000
--- a/svelte-code-block-themes/vite.config.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { defineConfig } from 'vite'
-import { svelte } from '@sveltejs/vite-plugin-svelte'
-import tailwindcss from '@tailwindcss/vite'
-
-// https://vitejs.dev/config/
-export default defineConfig({
-  plugins: [svelte(), tailwindcss()],
-})
diff --git a/svelte-code-block/.gitignore b/svelte-code-block/.gitignore
deleted file mode 100644
index 5d6225c6df..0000000000
--- a/svelte-code-block/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-dist
-.next
-.svelte-kit
diff --git a/svelte-code-block/README.md b/svelte-code-block/README.md
deleted file mode 100644
index 0230ffd133..0000000000
--- a/svelte-code-block/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# svelte-code-block
-
-A [ProseKit](https://prosekit.dev) example.
-
-[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-code-block)
-[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-code-block)
-
-Run the example locally with:
-
-```bash
-npx degit prosekit/examples/svelte-code-block svelte-code-block
-cd svelte-code-block
-npm install
-npm run dev
-```
diff --git a/svelte-code-block/index.html b/svelte-code-block/index.html
deleted file mode 100644
index 58212c2501..0000000000
--- a/svelte-code-block/index.html
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-  
-    
-    
-    ProseKit + Svelte
-  
-  
-    
- - - diff --git a/svelte-code-block/package.json b/svelte-code-block/package.json deleted file mode 100644 index ef5a708265..0000000000 --- a/svelte-code-block/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-code-block", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-code-block/src/App.svelte b/svelte-code-block/src/App.svelte deleted file mode 100644 index c4e6b48f16..0000000000 --- a/svelte-code-block/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-code-block/src/app.css b/svelte-code-block/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-code-block/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-code-block/src/components/editor/examples/code-block/editor.svelte b/svelte-code-block/src/components/editor/examples/code-block/editor.svelte deleted file mode 100644 index d983b9dd39..0000000000 --- a/svelte-code-block/src/components/editor/examples/code-block/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-code-block/src/components/editor/examples/code-block/extension.ts b/svelte-code-block/src/components/editor/examples/code-block/extension.ts deleted file mode 100644 index 099cacf03b..0000000000 --- a/svelte-code-block/src/components/editor/examples/code-block/extension.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { - defineCodeBlock, - defineCodeBlockShiki, -} from 'prosekit/extensions/code-block' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCodeBlock(), - defineCodeBlockShiki(), - defineCodeBlockView(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-code-block/src/components/editor/examples/code-block/index.ts b/svelte-code-block/src/components/editor/examples/code-block/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-code-block/src/components/editor/examples/code-block/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-code-block/src/components/editor/sample/sample-doc-code-block.ts b/svelte-code-block/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/svelte-code-block/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/svelte-code-block/src/components/editor/ui/button/button.svelte b/svelte-code-block/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-code-block/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-code-block/src/components/editor/ui/button/index.ts b/svelte-code-block/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-code-block/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-code-block/src/components/editor/ui/code-block-view/code-block-view.svelte b/svelte-code-block/src/components/editor/ui/code-block-view/code-block-view.svelte deleted file mode 100644 index aaa4617fc1..0000000000 --- a/svelte-code-block/src/components/editor/ui/code-block-view/code-block-view.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - -

diff --git a/svelte-code-block/src/components/editor/ui/code-block-view/index.ts b/svelte-code-block/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index eb54b2f6d9..0000000000
--- a/svelte-code-block/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSvelteNodeView,
-  type SvelteNodeViewComponent,
-} from 'prosekit/svelte'
-
-import CodeBlockView from './code-block-view.svelte'
-
-export function defineCodeBlockView(): Extension {
-  return defineSvelteNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView as SvelteNodeViewComponent,
-  })
-}
diff --git a/svelte-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
deleted file mode 100644
index c80af45721..0000000000
--- a/svelte-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-  
-    
-  
-
-  
-      {#if !file}
-        
-        
-      {/if}
-
-      {#if !url}
-        
-        
-      {/if}
-
-      {#if url}
-        
-      {/if}
-
-      {#if file}
-        
-      {/if}
-    
-
diff --git a/svelte-code-block/src/components/editor/ui/image-upload-popover/index.ts b/svelte-code-block/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index e53e71c348..0000000000
--- a/svelte-code-block/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover.svelte'
diff --git a/svelte-code-block/src/components/editor/ui/toolbar/index.ts b/svelte-code-block/src/components/editor/ui/toolbar/index.ts
deleted file mode 100644
index 7b55cca073..0000000000
--- a/svelte-code-block/src/components/editor/ui/toolbar/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as Toolbar } from './toolbar.svelte'
diff --git a/svelte-code-block/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-code-block/src/components/editor/ui/toolbar/toolbar.svelte
deleted file mode 100644
index 49bbeff5aa..0000000000
--- a/svelte-code-block/src/components/editor/ui/toolbar/toolbar.svelte
+++ /dev/null
@@ -1,365 +0,0 @@
-
-
-
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-code-block/src/main.ts b/svelte-code-block/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-code-block/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-code-block/src/vite-env.d.ts b/svelte-code-block/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-code-block/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-code-block/svelte.config.js b/svelte-code-block/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-code-block/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-code-block/tsconfig.json b/svelte-code-block/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-code-block/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-code-block/tsconfig.node.json b/svelte-code-block/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-code-block/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-code-block/vite.config.ts b/svelte-code-block/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-code-block/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-code/.gitignore b/svelte-code/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-code/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-code/README.md b/svelte-code/README.md deleted file mode 100644 index 0817bfa3ca..0000000000 --- a/svelte-code/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-code - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-code) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-code) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-code svelte-code -cd svelte-code -npm install -npm run dev -``` diff --git a/svelte-code/index.html b/svelte-code/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-code/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-code/package.json b/svelte-code/package.json deleted file mode 100644 index e6016529f2..0000000000 --- a/svelte-code/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-code", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-code/src/App.svelte b/svelte-code/src/App.svelte deleted file mode 100644 index e77af1e003..0000000000 --- a/svelte-code/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-code/src/app.css b/svelte-code/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-code/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-code/src/components/editor/examples/code/editor.svelte b/svelte-code/src/components/editor/examples/code/editor.svelte deleted file mode 100644 index e47d53633d..0000000000 --- a/svelte-code/src/components/editor/examples/code/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-code/src/components/editor/examples/code/extension.ts b/svelte-code/src/components/editor/examples/code/extension.ts deleted file mode 100644 index e9e273216e..0000000000 --- a/svelte-code/src/components/editor/examples/code/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCode(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-code/src/components/editor/examples/code/index.ts b/svelte-code/src/components/editor/examples/code/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-code/src/components/editor/examples/code/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-code/src/components/editor/sample/sample-doc-code.ts b/svelte-code/src/components/editor/sample/sample-doc-code.ts deleted file mode 100644 index 2fdbcee1f3..0000000000 --- a/svelte-code/src/components/editor/sample/sample-doc-code.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'This is code', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/svelte-code/src/components/editor/ui/button/button.svelte b/svelte-code/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-code/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-code/src/components/editor/ui/button/index.ts b/svelte-code/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-code/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-code/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-code/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-code/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-code/src/components/editor/ui/image-upload-popover/index.ts b/svelte-code/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-code/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-code/src/components/editor/ui/toolbar/index.ts b/svelte-code/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-code/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-code/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-code/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-code/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-code/src/main.ts b/svelte-code/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-code/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-code/src/vite-env.d.ts b/svelte-code/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-code/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-code/svelte.config.js b/svelte-code/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-code/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-code/tsconfig.json b/svelte-code/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-code/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-code/tsconfig.node.json b/svelte-code/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-code/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-code/vite.config.ts b/svelte-code/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-code/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-drop-cursor/.gitignore b/svelte-drop-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-drop-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-drop-cursor/README.md b/svelte-drop-cursor/README.md deleted file mode 100644 index 022678b9f8..0000000000 --- a/svelte-drop-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-drop-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-drop-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-drop-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-drop-cursor svelte-drop-cursor -cd svelte-drop-cursor -npm install -npm run dev -``` diff --git a/svelte-drop-cursor/index.html b/svelte-drop-cursor/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-drop-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-drop-cursor/package.json b/svelte-drop-cursor/package.json deleted file mode 100644 index f88cfbadf2..0000000000 --- a/svelte-drop-cursor/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-drop-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-drop-cursor/src/App.svelte b/svelte-drop-cursor/src/App.svelte deleted file mode 100644 index 4c88b27ec9..0000000000 --- a/svelte-drop-cursor/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-drop-cursor/src/app.css b/svelte-drop-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-drop-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/editor.svelte b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/editor.svelte deleted file mode 100644 index 2de79d237f..0000000000 --- a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/editor.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts deleted file mode 100644 index fd79a2c96c..0000000000 --- a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineImage(), - defineDropCursor({ - color: false, - width: 4, - class: 'transition-all bg-blue-500', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/svelte-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts deleted file mode 100644 index 22c6b93465..0000000000 --- a/svelte-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the images below to see the custom drop cursor.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/320x240/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/green/320x240/40', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blue/320x240/187', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/red/320x240/188', - }, - }, - ], -} diff --git a/svelte-drop-cursor/src/main.ts b/svelte-drop-cursor/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-drop-cursor/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-drop-cursor/src/vite-env.d.ts b/svelte-drop-cursor/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-drop-cursor/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-drop-cursor/svelte.config.js b/svelte-drop-cursor/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-drop-cursor/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-drop-cursor/tsconfig.json b/svelte-drop-cursor/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-drop-cursor/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-drop-cursor/tsconfig.node.json b/svelte-drop-cursor/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-drop-cursor/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-drop-cursor/vite.config.ts b/svelte-drop-cursor/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-drop-cursor/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-emoji-rules/.gitignore b/svelte-emoji-rules/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-emoji-rules/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-emoji-rules/README.md b/svelte-emoji-rules/README.md deleted file mode 100644 index a634bfb847..0000000000 --- a/svelte-emoji-rules/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-emoji-rules - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-emoji-rules) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-emoji-rules) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-emoji-rules svelte-emoji-rules -cd svelte-emoji-rules -npm install -npm run dev -``` diff --git a/svelte-emoji-rules/index.html b/svelte-emoji-rules/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-emoji-rules/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-emoji-rules/package.json b/svelte-emoji-rules/package.json deleted file mode 100644 index e572857f33..0000000000 --- a/svelte-emoji-rules/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-emoji-rules", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-emoji-rules/src/App.svelte b/svelte-emoji-rules/src/App.svelte deleted file mode 100644 index 7d5cc766ba..0000000000 --- a/svelte-emoji-rules/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-emoji-rules/src/app.css b/svelte-emoji-rules/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-emoji-rules/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/editor.svelte b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/editor.svelte deleted file mode 100644 index 03b6c9f2ca..0000000000 --- a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/editor.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts deleted file mode 100644 index 5cac9cbc79..0000000000 --- a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineEnterRule } from 'prosekit/extensions/enter-rule' - -/** - * Converts the text before the text cursor into an emoji when pressing `Enter`. - */ -export function defineEmojiEnterRule() { - return defineEnterRule({ - regex: /:(apple|banana):$/, - handler: ({ match, from, to, state }) => { - const text = match[1] as 'apple' | 'banana' - const emoji = text === 'apple' ? '🍎' : '🍌' - return state.tr.replaceWith(from, to, state.schema.text(emoji)) - }, - }) -} diff --git a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts deleted file mode 100644 index bc9bcb8412..0000000000 --- a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { defineEmojiEnterRule } from './emoji' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineEmojiEnterRule(), - definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-emoji-rules/src/main.ts b/svelte-emoji-rules/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-emoji-rules/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-emoji-rules/src/vite-env.d.ts b/svelte-emoji-rules/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-emoji-rules/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-emoji-rules/svelte.config.js b/svelte-emoji-rules/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-emoji-rules/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-emoji-rules/tsconfig.json b/svelte-emoji-rules/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-emoji-rules/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-emoji-rules/tsconfig.node.json b/svelte-emoji-rules/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-emoji-rules/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-emoji-rules/vite.config.ts b/svelte-emoji-rules/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-emoji-rules/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-full/.gitignore b/svelte-full/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-full/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-full/README.md b/svelte-full/README.md deleted file mode 100644 index fb6da41106..0000000000 --- a/svelte-full/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-full - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-full) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-full) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-full svelte-full -cd svelte-full -npm install -npm run dev -``` diff --git a/svelte-full/index.html b/svelte-full/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-full/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-full/package.json b/svelte-full/package.json deleted file mode 100644 index 165bb65c02..0000000000 --- a/svelte-full/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-svelte-full", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-full/src/App.svelte b/svelte-full/src/App.svelte deleted file mode 100644 index 55103feeed..0000000000 --- a/svelte-full/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-full/src/app.css b/svelte-full/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-full/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-full/src/components/editor/examples/full/editor.svelte b/svelte-full/src/components/editor/examples/full/editor.svelte deleted file mode 100644 index 09f3d7d9d3..0000000000 --- a/svelte-full/src/components/editor/examples/full/editor.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - - -
- -
-
- - - - - - - -
-
-
diff --git a/svelte-full/src/components/editor/examples/full/extension.ts b/svelte-full/src/components/editor/examples/full/extension.ts deleted file mode 100644 index 5fc2f60685..0000000000 --- a/svelte-full/src/components/editor/examples/full/extension.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineImageUploadHandler } from 'prosekit/extensions/image' -import { defineMath } from 'prosekit/extensions/math' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' -import { sampleUploader } from '../../sample/sample-uploader' -import { defineCodeBlockView } from '../../ui/code-block-view' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - defineMention(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - defineCodeBlockShiki(), - defineHorizontalRule(), - defineCodeBlockView(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-full/src/components/editor/examples/full/index.ts b/svelte-full/src/components/editor/examples/full/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-full/src/components/editor/examples/full/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-full/src/components/editor/sample/katex.ts b/svelte-full/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/svelte-full/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/svelte-full/src/components/editor/sample/sample-doc-full.ts b/svelte-full/src/components/editor/sample/sample-doc-full.ts deleted file mode 100644 index 13e49b634d..0000000000 --- a/svelte-full/src/components/editor/sample/sample-doc-full.ts +++ /dev/null @@ -1,442 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'The editor that thinks like you' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', - }, - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'writing without barriers', - }, - { type: 'text', text: '.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Text that shines.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Make your words ' }, - { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, - { type: 'text', text: ', or ' }, - { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, - { type: 'text', text: '. Add ' }, - { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, - { type: 'text', text: ' that stands out. Create ' }, - { - type: 'text', - marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], - text: 'links', - }, - { type: 'text', text: ' that connect.' }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Select any text to format it. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '@' }, - { type: 'text', text: ' to mention ' }, - { - type: 'mention', - attrs: { id: '39', value: '@someone', kind: 'user' }, - }, - { type: 'text', text: ' or ' }, - { type: 'text', marks: [{ type: 'code' }], text: '#' }, - { type: 'text', text: ' for ' }, - { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, - { type: 'text', text: '. Press ' }, - { type: 'text', marks: [{ type: 'code' }], text: '/' }, - { type: 'text', text: " and discover what's possible." }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Lists that organize.' }], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Bullet points that guide thoughts' }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Nested lists for complex ideas' }], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sub-points flow naturally' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Tasks that focus' }], - }, - { - type: 'list', - attrs: { kind: 'task', order: null, checked: true, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Done feels good' }], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Todo drives action' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Numbered steps' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sequential thinking' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Clear progress' }], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Code that inspires.' }], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Images that captivate.' }], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/season/320x240/107', - }, - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the handle in the bottom right corner to resize.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Tables that structure.' }], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'Feature', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'How to use', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Format text' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Select and choose' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Perfect styling' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Add mentions' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Type @ and name' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Connected ideas' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Insert anything' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Press / for menu' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Endless possibilities' }], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Math that renders.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Inline math like ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' appears within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Quotes that inspire.' }], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: '"This is not just an editor. This is how writing should feel."', - }, - ], - }, - ], - }, - { type: 'horizontalRule' }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Start typing. Everything else just flows.' }, - ], - }, - ], -} diff --git a/svelte-full/src/components/editor/sample/sample-tag-data.ts b/svelte-full/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/svelte-full/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/svelte-full/src/components/editor/sample/sample-uploader.ts b/svelte-full/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/svelte-full/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/svelte-full/src/components/editor/sample/sample-user-data.ts b/svelte-full/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/svelte-full/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/svelte-full/src/components/editor/ui/block-handle/block-handle.svelte b/svelte-full/src/components/editor/ui/block-handle/block-handle.svelte deleted file mode 100644 index f67e42dc91..0000000000 --- a/svelte-full/src/components/editor/ui/block-handle/block-handle.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - -
-
- -
-
-
-
-
diff --git a/svelte-full/src/components/editor/ui/block-handle/index.ts b/svelte-full/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 6d21191384..0000000000 --- a/svelte-full/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.svelte' diff --git a/svelte-full/src/components/editor/ui/button/button.svelte b/svelte-full/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-full/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-full/src/components/editor/ui/button/index.ts b/svelte-full/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-full/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-full/src/components/editor/ui/code-block-view/code-block-view.svelte b/svelte-full/src/components/editor/ui/code-block-view/code-block-view.svelte deleted file mode 100644 index aaa4617fc1..0000000000 --- a/svelte-full/src/components/editor/ui/code-block-view/code-block-view.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - -

diff --git a/svelte-full/src/components/editor/ui/code-block-view/index.ts b/svelte-full/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index eb54b2f6d9..0000000000
--- a/svelte-full/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSvelteNodeView,
-  type SvelteNodeViewComponent,
-} from 'prosekit/svelte'
-
-import CodeBlockView from './code-block-view.svelte'
-
-export function defineCodeBlockView(): Extension {
-  return defineSvelteNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView as SvelteNodeViewComponent,
-  })
-}
diff --git a/svelte-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/svelte-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte
deleted file mode 100644
index 7f6cac1db0..0000000000
--- a/svelte-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/svelte-full/src/components/editor/ui/drop-indicator/index.ts b/svelte-full/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index 06e89357ed..0000000000
--- a/svelte-full/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator.svelte'
diff --git a/svelte-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
deleted file mode 100644
index c80af45721..0000000000
--- a/svelte-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-  
-    
-  
-
-  
-      {#if !file}
-        
-        
-      {/if}
-
-      {#if !url}
-        
-        
-      {/if}
-
-      {#if url}
-        
-      {/if}
-
-      {#if file}
-        
-      {/if}
-    
-
diff --git a/svelte-full/src/components/editor/ui/image-upload-popover/index.ts b/svelte-full/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index e53e71c348..0000000000
--- a/svelte-full/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover.svelte'
diff --git a/svelte-full/src/components/editor/ui/image-view/image-view.svelte b/svelte-full/src/components/editor/ui/image-view/image-view.svelte
deleted file mode 100644
index b8f0fd3971..0000000000
--- a/svelte-full/src/components/editor/ui/image-view/image-view.svelte
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
- props.setAttrs(event.detail)}
->
-  {#if url && !error}
-    upload preview
-  {/if}
-  {#if uploading && !error}
-    
-
-
{Math.round(progress * 100)}%
-
- {/if} - {#if error} -
-
- -
- {/if} - -
-
-
diff --git a/svelte-full/src/components/editor/ui/image-view/index.ts b/svelte-full/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index d39bdb81e8..0000000000 --- a/svelte-full/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - defineSvelteNodeView, - type SvelteNodeViewComponent, -} from 'prosekit/svelte' - -import ImageView from './image-view.svelte' - -export function defineImageView(): Extension { - return defineSvelteNodeView({ - name: 'image', - component: ImageView as SvelteNodeViewComponent, - }) -} diff --git a/svelte-full/src/components/editor/ui/inline-menu/index.ts b/svelte-full/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index bf78dd2139..0000000000 --- a/svelte-full/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-full/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-full/src/components/editor/ui/inline-menu/inline-menu.svelte deleted file mode 100644 index 989f0c013b..0000000000 --- a/svelte-full/src/components/editor/ui/inline-menu/inline-menu.svelte +++ /dev/null @@ -1,207 +0,0 @@ - - - { - if (!event.detail) linkMenuOpen = false - }} -> - - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.link?.canExec && $items.link} - - {/if} - - - - - { - linkMenuOpen = event.detail - }} -> - - - {#if linkMenuOpen && $items.link} -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- {/if} - {#if $items.link?.isActive} - - {/if} -
-
-
diff --git a/svelte-full/src/components/editor/ui/slash-menu/index.ts b/svelte-full/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 856d4e6b43..0000000000 --- a/svelte-full/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu.svelte' diff --git a/svelte-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte b/svelte-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte deleted file mode 100644 index 37cea8de67..0000000000 --- a/svelte-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - - No results - diff --git a/svelte-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte b/svelte-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte deleted file mode 100644 index 52126eeb68..0000000000 --- a/svelte-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte +++ /dev/null @@ -1,15 +0,0 @@ - - - - {props.label}{#if props.kbd}{props.kbd}{/if} - diff --git a/svelte-full/src/components/editor/ui/slash-menu/slash-menu.svelte b/svelte-full/src/components/editor/ui/slash-menu/slash-menu.svelte deleted file mode 100644 index 5da516b44f..0000000000 --- a/svelte-full/src/components/editor/ui/slash-menu/slash-menu.svelte +++ /dev/null @@ -1,94 +0,0 @@ - - - - - -
- $editor.commands.setParagraph()} - /> - - $editor.commands.setHeading({ level: 1 })} - /> - - $editor.commands.setHeading({ level: 2 })} - /> - - $editor.commands.setHeading({ level: 3 })} - /> - - $editor.commands.wrapInList({ kind: 'bullet' })} - /> - - $editor.commands.wrapInList({ kind: 'ordered' })} - /> - - $editor.commands.wrapInList({ kind: 'task' })} - /> - - $editor.commands.wrapInList({ kind: 'toggle' })} - /> - - $editor.commands.setBlockquote()} - /> - - $editor.commands.insertTable({ row: 3, col: 3 })} - /> - - $editor.commands.insertHorizontalRule()} - /> - - $editor.commands.setCodeBlock()} - /> - - -
-
-
-
diff --git a/svelte-full/src/components/editor/ui/table-handle/index.ts b/svelte-full/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 308cef59de..0000000000 --- a/svelte-full/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle.svelte' diff --git a/svelte-full/src/components/editor/ui/table-handle/table-handle.svelte b/svelte-full/src/components/editor/ui/table-handle/table-handle.svelte deleted file mode 100644 index fc91f9a438..0000000000 --- a/svelte-full/src/components/editor/ui/table-handle/table-handle.svelte +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - -
-
- - - {#if $state.addTableColumnBefore.canExec} - - Insert Left - - {/if} - {#if $state.addTableColumnAfter.canExec} - - Insert Right - - {/if} - {#if $state.deleteCellSelection.canExec} - - Clear Contents - Del - - {/if} - {#if $state.deleteTableColumn.canExec} - - Delete Column - - {/if} - {#if $state.deleteTable.canExec} - - Delete Table - - {/if} - - -
-
-
- - - - -
-
- - - {#if $state.addTableRowAbove.canExec} - - Insert Above - - {/if} - {#if $state.addTableRowBelow.canExec} - - Insert Below - - {/if} - {#if $state.deleteCellSelection.canExec} - - Clear Contents - Del - - {/if} - {#if $state.deleteTableRow.canExec} - - Delete Row - - {/if} - {#if $state.deleteTable.canExec} - - Delete Table - - {/if} - - -
-
-
-
diff --git a/svelte-full/src/components/editor/ui/tag-menu/index.ts b/svelte-full/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index 0884d7f5a1..0000000000 --- a/svelte-full/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu.svelte' diff --git a/svelte-full/src/components/editor/ui/tag-menu/tag-menu.svelte b/svelte-full/src/components/editor/ui/tag-menu/tag-menu.svelte deleted file mode 100644 index 8b9bf23f30..0000000000 --- a/svelte-full/src/components/editor/ui/tag-menu/tag-menu.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
- - No results - - - {#each props.tags as tag (tag.id)} - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - {/each} -
-
-
-
diff --git a/svelte-full/src/components/editor/ui/toolbar/index.ts b/svelte-full/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-full/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-full/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-full/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-full/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-full/src/components/editor/ui/user-menu/index.ts b/svelte-full/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index 7dbbd80d0e..0000000000 --- a/svelte-full/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu.svelte' diff --git a/svelte-full/src/components/editor/ui/user-menu/user-menu.svelte b/svelte-full/src/components/editor/ui/user-menu/user-menu.svelte deleted file mode 100644 index 5c0475d87e..0000000000 --- a/svelte-full/src/components/editor/ui/user-menu/user-menu.svelte +++ /dev/null @@ -1,70 +0,0 @@ - - - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} -> - - -
- - {loading ? 'Loading...' : 'No results'} - - - {#each props.users as user (user.id)} - handleUserInsert(user.id, user.name)} - > - {#if loading} - - {user.name} - - {:else} - - {user.name} - - {/if} - - {/each} -
-
-
-
diff --git a/svelte-full/src/main.ts b/svelte-full/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-full/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-full/src/vite-env.d.ts b/svelte-full/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-full/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-full/svelte.config.js b/svelte-full/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-full/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-full/tsconfig.json b/svelte-full/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-full/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-full/tsconfig.node.json b/svelte-full/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-full/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-full/vite.config.ts b/svelte-full/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-full/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-gap-cursor/.gitignore b/svelte-gap-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-gap-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-gap-cursor/README.md b/svelte-gap-cursor/README.md deleted file mode 100644 index da5cd4ead9..0000000000 --- a/svelte-gap-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-gap-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-gap-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-gap-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-gap-cursor svelte-gap-cursor -cd svelte-gap-cursor -npm install -npm run dev -``` diff --git a/svelte-gap-cursor/index.html b/svelte-gap-cursor/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-gap-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-gap-cursor/package.json b/svelte-gap-cursor/package.json deleted file mode 100644 index 58f93a4810..0000000000 --- a/svelte-gap-cursor/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-gap-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-gap-cursor/src/App.svelte b/svelte-gap-cursor/src/App.svelte deleted file mode 100644 index 7380fa3b5d..0000000000 --- a/svelte-gap-cursor/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-gap-cursor/src/app.css b/svelte-gap-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-gap-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/editor.svelte b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/editor.svelte deleted file mode 100644 index 00c2148aa1..0000000000 --- a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/editor.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts deleted file mode 100644 index 599497170d..0000000000 --- a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineGapCursor(), - defineImage(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/svelte-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts deleted file mode 100644 index e40ee2a83b..0000000000 --- a/svelte-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - ], -} diff --git a/svelte-gap-cursor/src/main.ts b/svelte-gap-cursor/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-gap-cursor/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-gap-cursor/src/vite-env.d.ts b/svelte-gap-cursor/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-gap-cursor/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-gap-cursor/svelte.config.js b/svelte-gap-cursor/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-gap-cursor/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-gap-cursor/tsconfig.json b/svelte-gap-cursor/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-gap-cursor/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-gap-cursor/tsconfig.node.json b/svelte-gap-cursor/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-gap-cursor/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-gap-cursor/vite.config.ts b/svelte-gap-cursor/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-gap-cursor/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-hard-break/.gitignore b/svelte-hard-break/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-hard-break/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-hard-break/README.md b/svelte-hard-break/README.md deleted file mode 100644 index 702c6a5208..0000000000 --- a/svelte-hard-break/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-hard-break - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-hard-break) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-hard-break) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-hard-break svelte-hard-break -cd svelte-hard-break -npm install -npm run dev -``` diff --git a/svelte-hard-break/index.html b/svelte-hard-break/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-hard-break/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-hard-break/package.json b/svelte-hard-break/package.json deleted file mode 100644 index 0af4fba623..0000000000 --- a/svelte-hard-break/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-hard-break", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-hard-break/src/App.svelte b/svelte-hard-break/src/App.svelte deleted file mode 100644 index fa30b62cc3..0000000000 --- a/svelte-hard-break/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-hard-break/src/app.css b/svelte-hard-break/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-hard-break/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-hard-break/src/components/editor/examples/hard-break/editor.svelte b/svelte-hard-break/src/components/editor/examples/hard-break/editor.svelte deleted file mode 100644 index c431ae655a..0000000000 --- a/svelte-hard-break/src/components/editor/examples/hard-break/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-hard-break/src/components/editor/examples/hard-break/extension.ts b/svelte-hard-break/src/components/editor/examples/hard-break/extension.ts deleted file mode 100644 index cad2881056..0000000000 --- a/svelte-hard-break/src/components/editor/examples/hard-break/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHardBreak } from 'prosekit/extensions/hard-break' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHardBreak(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-hard-break/src/components/editor/examples/hard-break/index.ts b/svelte-hard-break/src/components/editor/examples/hard-break/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-hard-break/src/components/editor/examples/hard-break/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-hard-break/src/components/editor/examples/hard-break/toolbar.svelte b/svelte-hard-break/src/components/editor/examples/hard-break/toolbar.svelte deleted file mode 100644 index d558b234ea..0000000000 --- a/svelte-hard-break/src/components/editor/examples/hard-break/toolbar.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - -
- -
diff --git a/svelte-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/svelte-hard-break/src/components/editor/sample/sample-doc-hard-break.ts deleted file mode 100644 index e1c9786b72..0000000000 --- a/svelte-hard-break/src/components/editor/sample/sample-doc-hard-break.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: "O'er all the hilltops", - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Is quiet now,', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'In all the treetops', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hearest thou', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hardly a breath;', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'The birds are asleep in the trees:', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Wait, soon like these', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Thou too shalt rest.', - }, - { - type: 'hardBreak', - }, - ], - }, - ], -} diff --git a/svelte-hard-break/src/components/editor/ui/button/button.svelte b/svelte-hard-break/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-hard-break/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-hard-break/src/components/editor/ui/button/index.ts b/svelte-hard-break/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-hard-break/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-hard-break/src/main.ts b/svelte-hard-break/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-hard-break/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-hard-break/src/vite-env.d.ts b/svelte-hard-break/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-hard-break/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-hard-break/svelte.config.js b/svelte-hard-break/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-hard-break/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-hard-break/tsconfig.json b/svelte-hard-break/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-hard-break/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-hard-break/tsconfig.node.json b/svelte-hard-break/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-hard-break/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-hard-break/vite.config.ts b/svelte-hard-break/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-hard-break/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-heading/.gitignore b/svelte-heading/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-heading/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-heading/README.md b/svelte-heading/README.md deleted file mode 100644 index 56b4c5ec1f..0000000000 --- a/svelte-heading/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-heading - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-heading) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-heading) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-heading svelte-heading -cd svelte-heading -npm install -npm run dev -``` diff --git a/svelte-heading/index.html b/svelte-heading/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-heading/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-heading/package.json b/svelte-heading/package.json deleted file mode 100644 index 7004299727..0000000000 --- a/svelte-heading/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-heading", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-heading/src/App.svelte b/svelte-heading/src/App.svelte deleted file mode 100644 index 20ae91e9ec..0000000000 --- a/svelte-heading/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-heading/src/app.css b/svelte-heading/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-heading/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-heading/src/components/editor/examples/heading/editor.svelte b/svelte-heading/src/components/editor/examples/heading/editor.svelte deleted file mode 100644 index 3933196cd5..0000000000 --- a/svelte-heading/src/components/editor/examples/heading/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-heading/src/components/editor/examples/heading/extension.ts b/svelte-heading/src/components/editor/examples/heading/extension.ts deleted file mode 100644 index e4f8e6ace0..0000000000 --- a/svelte-heading/src/components/editor/examples/heading/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHeading(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-heading/src/components/editor/examples/heading/index.ts b/svelte-heading/src/components/editor/examples/heading/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-heading/src/components/editor/examples/heading/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-heading/src/components/editor/sample/sample-doc-heading.ts b/svelte-heading/src/components/editor/sample/sample-doc-heading.ts deleted file mode 100644 index 210497e633..0000000000 --- a/svelte-heading/src/components/editor/sample/sample-doc-heading.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'H1' }], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'H2' }], - }, - { - type: 'heading', - attrs: { level: 3 }, - content: [{ type: 'text', text: 'H3' }], - }, - { type: 'paragraph', content: [] }, - ], -} diff --git a/svelte-heading/src/components/editor/ui/button/button.svelte b/svelte-heading/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-heading/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-heading/src/components/editor/ui/button/index.ts b/svelte-heading/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-heading/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-heading/src/components/editor/ui/image-upload-popover/index.ts b/svelte-heading/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-heading/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-heading/src/components/editor/ui/toolbar/index.ts b/svelte-heading/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-heading/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-heading/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-heading/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-heading/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-heading/src/main.ts b/svelte-heading/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-heading/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-heading/src/vite-env.d.ts b/svelte-heading/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-heading/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-heading/svelte.config.js b/svelte-heading/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-heading/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-heading/tsconfig.json b/svelte-heading/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-heading/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-heading/tsconfig.node.json b/svelte-heading/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-heading/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-heading/vite.config.ts b/svelte-heading/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-heading/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-highlight/.gitignore b/svelte-highlight/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-highlight/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-highlight/README.md b/svelte-highlight/README.md deleted file mode 100644 index 879f073aa2..0000000000 --- a/svelte-highlight/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-highlight - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-highlight) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-highlight) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-highlight svelte-highlight -cd svelte-highlight -npm install -npm run dev -``` diff --git a/svelte-highlight/index.html b/svelte-highlight/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-highlight/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-highlight/package.json b/svelte-highlight/package.json deleted file mode 100644 index d5d0161644..0000000000 --- a/svelte-highlight/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-highlight", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-highlight/src/App.svelte b/svelte-highlight/src/App.svelte deleted file mode 100644 index 1183340f4a..0000000000 --- a/svelte-highlight/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-highlight/src/app.css b/svelte-highlight/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-highlight/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-highlight/src/components/editor/examples/highlight/editor.svelte b/svelte-highlight/src/components/editor/examples/highlight/editor.svelte deleted file mode 100644 index 90d6bcada7..0000000000 --- a/svelte-highlight/src/components/editor/examples/highlight/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-highlight/src/components/editor/examples/highlight/extension.ts b/svelte-highlight/src/components/editor/examples/highlight/extension.ts deleted file mode 100644 index abc131c3be..0000000000 --- a/svelte-highlight/src/components/editor/examples/highlight/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHighlight } from 'prosekit/extensions/highlight' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHighlight(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-highlight/src/components/editor/examples/highlight/index.ts b/svelte-highlight/src/components/editor/examples/highlight/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-highlight/src/components/editor/examples/highlight/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-highlight/src/components/editor/examples/highlight/toolbar.svelte b/svelte-highlight/src/components/editor/examples/highlight/toolbar.svelte deleted file mode 100644 index 5c1e9f3896..0000000000 --- a/svelte-highlight/src/components/editor/examples/highlight/toolbar.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - -
- -
diff --git a/svelte-highlight/src/components/editor/sample/sample-doc-highlight.ts b/svelte-highlight/src/components/editor/sample/sample-doc-highlight.ts deleted file mode 100644 index 0de1a1f7b2..0000000000 --- a/svelte-highlight/src/components/editor/sample/sample-doc-highlight.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'highlight', - }, - ], - text: 'This is highlighted text', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/svelte-highlight/src/components/editor/ui/button/button.svelte b/svelte-highlight/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-highlight/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-highlight/src/components/editor/ui/button/index.ts b/svelte-highlight/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-highlight/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-highlight/src/main.ts b/svelte-highlight/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-highlight/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-highlight/src/vite-env.d.ts b/svelte-highlight/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-highlight/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-highlight/svelte.config.js b/svelte-highlight/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-highlight/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-highlight/tsconfig.json b/svelte-highlight/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-highlight/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-highlight/tsconfig.node.json b/svelte-highlight/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-highlight/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-highlight/vite.config.ts b/svelte-highlight/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-highlight/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-horizontal-rule/.gitignore b/svelte-horizontal-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-horizontal-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-horizontal-rule/README.md b/svelte-horizontal-rule/README.md deleted file mode 100644 index 555c4c7853..0000000000 --- a/svelte-horizontal-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-horizontal-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-horizontal-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-horizontal-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-horizontal-rule svelte-horizontal-rule -cd svelte-horizontal-rule -npm install -npm run dev -``` diff --git a/svelte-horizontal-rule/index.html b/svelte-horizontal-rule/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-horizontal-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-horizontal-rule/package.json b/svelte-horizontal-rule/package.json deleted file mode 100644 index 71556d431b..0000000000 --- a/svelte-horizontal-rule/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-horizontal-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-horizontal-rule/src/App.svelte b/svelte-horizontal-rule/src/App.svelte deleted file mode 100644 index 36fa28d72c..0000000000 --- a/svelte-horizontal-rule/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-horizontal-rule/src/app.css b/svelte-horizontal-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-horizontal-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.svelte b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.svelte deleted file mode 100644 index 741b836c3c..0000000000 --- a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts deleted file mode 100644 index 49b6121eeb..0000000000 --- a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHorizontalRule(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-horizontal-rule/src/components/editor/ui/button/button.svelte b/svelte-horizontal-rule/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-horizontal-rule/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-horizontal-rule/src/components/editor/ui/button/index.ts b/svelte-horizontal-rule/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-horizontal-rule/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/svelte-horizontal-rule/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-horizontal-rule/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-horizontal-rule/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-horizontal-rule/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-horizontal-rule/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-horizontal-rule/src/main.ts b/svelte-horizontal-rule/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-horizontal-rule/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-horizontal-rule/src/vite-env.d.ts b/svelte-horizontal-rule/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-horizontal-rule/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-horizontal-rule/svelte.config.js b/svelte-horizontal-rule/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-horizontal-rule/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-horizontal-rule/tsconfig.json b/svelte-horizontal-rule/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-horizontal-rule/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-horizontal-rule/tsconfig.node.json b/svelte-horizontal-rule/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-horizontal-rule/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-horizontal-rule/vite.config.ts b/svelte-horizontal-rule/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-horizontal-rule/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-image-view/.gitignore b/svelte-image-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-image-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-image-view/README.md b/svelte-image-view/README.md deleted file mode 100644 index a69dc143f0..0000000000 --- a/svelte-image-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-image-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-image-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-image-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-image-view svelte-image-view -cd svelte-image-view -npm install -npm run dev -``` diff --git a/svelte-image-view/index.html b/svelte-image-view/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-image-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-image-view/package.json b/svelte-image-view/package.json deleted file mode 100644 index 88499c0dd3..0000000000 --- a/svelte-image-view/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-image-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-image-view/src/App.svelte b/svelte-image-view/src/App.svelte deleted file mode 100644 index 3417c3812d..0000000000 --- a/svelte-image-view/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-image-view/src/app.css b/svelte-image-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-image-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-image-view/src/components/editor/examples/image-view/editor.svelte b/svelte-image-view/src/components/editor/examples/image-view/editor.svelte deleted file mode 100644 index 6386d5867a..0000000000 --- a/svelte-image-view/src/components/editor/examples/image-view/editor.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-image-view/src/components/editor/examples/image-view/extension.ts b/svelte-image-view/src/components/editor/examples/image-view/extension.ts deleted file mode 100644 index a21febf634..0000000000 --- a/svelte-image-view/src/components/editor/examples/image-view/extension.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineImageUploadHandler } from 'prosekit/extensions/image' - -import { sampleUploader } from '../../sample/sample-uploader' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-image-view/src/components/editor/examples/image-view/index.ts b/svelte-image-view/src/components/editor/examples/image-view/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-image-view/src/components/editor/examples/image-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-image-view/src/components/editor/sample/sample-doc-image.ts b/svelte-image-view/src/components/editor/sample/sample-doc-image.ts deleted file mode 100644 index c97628339d..0000000000 --- a/svelte-image-view/src/components/editor/sample/sample-doc-image.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Paste or drop an image to upload it.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/white/200x200/1', - width: 160, - height: 160, - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/640x360/42', - width: 240, - height: 135, - }, - }, - ], -} diff --git a/svelte-image-view/src/components/editor/sample/sample-uploader.ts b/svelte-image-view/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/svelte-image-view/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/svelte-image-view/src/components/editor/ui/image-view/image-view.svelte b/svelte-image-view/src/components/editor/ui/image-view/image-view.svelte deleted file mode 100644 index b8f0fd3971..0000000000 --- a/svelte-image-view/src/components/editor/ui/image-view/image-view.svelte +++ /dev/null @@ -1,97 +0,0 @@ - - - props.setAttrs(event.detail)} -> - {#if url && !error} - upload preview - {/if} - {#if uploading && !error} -
-
-
{Math.round(progress * 100)}%
-
- {/if} - {#if error} -
-
- -
- {/if} - -
-
-
diff --git a/svelte-image-view/src/components/editor/ui/image-view/index.ts b/svelte-image-view/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index d39bdb81e8..0000000000 --- a/svelte-image-view/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - defineSvelteNodeView, - type SvelteNodeViewComponent, -} from 'prosekit/svelte' - -import ImageView from './image-view.svelte' - -export function defineImageView(): Extension { - return defineSvelteNodeView({ - name: 'image', - component: ImageView as SvelteNodeViewComponent, - }) -} diff --git a/svelte-image-view/src/main.ts b/svelte-image-view/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-image-view/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-image-view/src/vite-env.d.ts b/svelte-image-view/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-image-view/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-image-view/svelte.config.js b/svelte-image-view/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-image-view/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-image-view/tsconfig.json b/svelte-image-view/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-image-view/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-image-view/tsconfig.node.json b/svelte-image-view/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-image-view/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-image-view/vite.config.ts b/svelte-image-view/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-image-view/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-inline-menu/.gitignore b/svelte-inline-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-inline-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-inline-menu/README.md b/svelte-inline-menu/README.md deleted file mode 100644 index 46d48f5663..0000000000 --- a/svelte-inline-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-inline-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-inline-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-inline-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-inline-menu svelte-inline-menu -cd svelte-inline-menu -npm install -npm run dev -``` diff --git a/svelte-inline-menu/index.html b/svelte-inline-menu/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-inline-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-inline-menu/package.json b/svelte-inline-menu/package.json deleted file mode 100644 index 4da47264bb..0000000000 --- a/svelte-inline-menu/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-inline-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-inline-menu/src/App.svelte b/svelte-inline-menu/src/App.svelte deleted file mode 100644 index 0a90100c19..0000000000 --- a/svelte-inline-menu/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-inline-menu/src/app.css b/svelte-inline-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-inline-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-inline-menu/src/components/editor/examples/inline-menu/editor.svelte b/svelte-inline-menu/src/components/editor/examples/inline-menu/editor.svelte deleted file mode 100644 index 1c85d78255..0000000000 --- a/svelte-inline-menu/src/components/editor/examples/inline-menu/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
-
-
- -
-
-
diff --git a/svelte-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/svelte-inline-menu/src/components/editor/examples/inline-menu/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/svelte-inline-menu/src/components/editor/examples/inline-menu/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/svelte-inline-menu/src/components/editor/examples/inline-menu/index.ts b/svelte-inline-menu/src/components/editor/examples/inline-menu/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-inline-menu/src/components/editor/examples/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/svelte-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts deleted file mode 100644 index 62a5984cb0..0000000000 --- a/svelte-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const loremText = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'Try to select some text', - }, - ], - }, - ...Array.from({ length: 10 }, () => ({ - type: 'paragraph' as const, - content: [ - { - type: 'text' as const, - text: loremText, - }, - ], - })), - ], -} diff --git a/svelte-inline-menu/src/components/editor/ui/button/button.svelte b/svelte-inline-menu/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-inline-menu/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-inline-menu/src/components/editor/ui/button/index.ts b/svelte-inline-menu/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-inline-menu/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-inline-menu/src/components/editor/ui/inline-menu/index.ts b/svelte-inline-menu/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index bf78dd2139..0000000000 --- a/svelte-inline-menu/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-inline-menu/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-inline-menu/src/components/editor/ui/inline-menu/inline-menu.svelte deleted file mode 100644 index 989f0c013b..0000000000 --- a/svelte-inline-menu/src/components/editor/ui/inline-menu/inline-menu.svelte +++ /dev/null @@ -1,207 +0,0 @@ - - - { - if (!event.detail) linkMenuOpen = false - }} -> - - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.link?.canExec && $items.link} - - {/if} - - - - - { - linkMenuOpen = event.detail - }} -> - - - {#if linkMenuOpen && $items.link} -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- {/if} - {#if $items.link?.isActive} - - {/if} -
-
-
diff --git a/svelte-inline-menu/src/main.ts b/svelte-inline-menu/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-inline-menu/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-inline-menu/src/vite-env.d.ts b/svelte-inline-menu/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-inline-menu/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-inline-menu/svelte.config.js b/svelte-inline-menu/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-inline-menu/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-inline-menu/tsconfig.json b/svelte-inline-menu/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-inline-menu/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-inline-menu/tsconfig.node.json b/svelte-inline-menu/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-inline-menu/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-inline-menu/vite.config.ts b/svelte-inline-menu/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-inline-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-italic/.gitignore b/svelte-italic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-italic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-italic/README.md b/svelte-italic/README.md deleted file mode 100644 index 26fe8e485b..0000000000 --- a/svelte-italic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-italic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-italic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-italic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-italic svelte-italic -cd svelte-italic -npm install -npm run dev -``` diff --git a/svelte-italic/index.html b/svelte-italic/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-italic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-italic/package.json b/svelte-italic/package.json deleted file mode 100644 index d95e3c4ae4..0000000000 --- a/svelte-italic/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-italic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-italic/src/App.svelte b/svelte-italic/src/App.svelte deleted file mode 100644 index 3a23fc7410..0000000000 --- a/svelte-italic/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-italic/src/app.css b/svelte-italic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-italic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-italic/src/components/editor/examples/italic/editor.svelte b/svelte-italic/src/components/editor/examples/italic/editor.svelte deleted file mode 100644 index 2b3d9d8c5b..0000000000 --- a/svelte-italic/src/components/editor/examples/italic/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-italic/src/components/editor/examples/italic/extension.ts b/svelte-italic/src/components/editor/examples/italic/extension.ts deleted file mode 100644 index a456b06aad..0000000000 --- a/svelte-italic/src/components/editor/examples/italic/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineItalic(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-italic/src/components/editor/examples/italic/index.ts b/svelte-italic/src/components/editor/examples/italic/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-italic/src/components/editor/examples/italic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-italic/src/components/editor/sample/sample-doc-italic.ts b/svelte-italic/src/components/editor/sample/sample-doc-italic.ts deleted file mode 100644 index fb99415b2c..0000000000 --- a/svelte-italic/src/components/editor/sample/sample-doc-italic.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/svelte-italic/src/components/editor/ui/button/button.svelte b/svelte-italic/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-italic/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-italic/src/components/editor/ui/button/index.ts b/svelte-italic/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-italic/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-italic/src/components/editor/ui/image-upload-popover/index.ts b/svelte-italic/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-italic/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-italic/src/components/editor/ui/toolbar/index.ts b/svelte-italic/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-italic/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-italic/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-italic/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-italic/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-italic/src/main.ts b/svelte-italic/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-italic/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-italic/src/vite-env.d.ts b/svelte-italic/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-italic/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-italic/svelte.config.js b/svelte-italic/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-italic/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-italic/tsconfig.json b/svelte-italic/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-italic/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-italic/tsconfig.node.json b/svelte-italic/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-italic/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-italic/vite.config.ts b/svelte-italic/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-italic/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-katex/.gitignore b/svelte-katex/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-katex/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-katex/README.md b/svelte-katex/README.md deleted file mode 100644 index 2a7247175a..0000000000 --- a/svelte-katex/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-katex - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-katex) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-katex) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-katex svelte-katex -cd svelte-katex -npm install -npm run dev -``` diff --git a/svelte-katex/index.html b/svelte-katex/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-katex/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-katex/package.json b/svelte-katex/package.json deleted file mode 100644 index 6b8345232e..0000000000 --- a/svelte-katex/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-svelte-katex", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-katex/src/App.svelte b/svelte-katex/src/App.svelte deleted file mode 100644 index 8b059f290e..0000000000 --- a/svelte-katex/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-katex/src/app.css b/svelte-katex/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-katex/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-katex/src/components/editor/examples/katex/editor.svelte b/svelte-katex/src/components/editor/examples/katex/editor.svelte deleted file mode 100644 index b4f078fbb4..0000000000 --- a/svelte-katex/src/components/editor/examples/katex/editor.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-katex/src/components/editor/examples/katex/extension.ts b/svelte-katex/src/components/editor/examples/katex/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/svelte-katex/src/components/editor/examples/katex/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-katex/src/components/editor/examples/katex/index.ts b/svelte-katex/src/components/editor/examples/katex/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-katex/src/components/editor/examples/katex/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-katex/src/components/editor/sample/katex.ts b/svelte-katex/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/svelte-katex/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/svelte-katex/src/components/editor/sample/sample-doc-tex.ts b/svelte-katex/src/components/editor/sample/sample-doc-tex.ts deleted file mode 100644 index 21ccf3e94e..0000000000 --- a/svelte-katex/src/components/editor/sample/sample-doc-tex.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Inline equations' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Block equations' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: 'The Gaussian integral:' }], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - ], -} diff --git a/svelte-katex/src/main.ts b/svelte-katex/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-katex/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-katex/src/vite-env.d.ts b/svelte-katex/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-katex/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-katex/svelte.config.js b/svelte-katex/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-katex/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-katex/tsconfig.json b/svelte-katex/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-katex/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-katex/tsconfig.node.json b/svelte-katex/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-katex/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-katex/vite.config.ts b/svelte-katex/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-katex/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-keymap/.gitignore b/svelte-keymap/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-keymap/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-keymap/README.md b/svelte-keymap/README.md deleted file mode 100644 index f1576889da..0000000000 --- a/svelte-keymap/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-keymap - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-keymap) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-keymap) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-keymap svelte-keymap -cd svelte-keymap -npm install -npm run dev -``` diff --git a/svelte-keymap/index.html b/svelte-keymap/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-keymap/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-keymap/package.json b/svelte-keymap/package.json deleted file mode 100644 index 3118f30d13..0000000000 --- a/svelte-keymap/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-keymap", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-keymap/src/App.svelte b/svelte-keymap/src/App.svelte deleted file mode 100644 index d8811f6ba4..0000000000 --- a/svelte-keymap/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-keymap/src/app.css b/svelte-keymap/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-keymap/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-keymap/src/components/editor/examples/keymap/editor.svelte b/svelte-keymap/src/components/editor/examples/keymap/editor.svelte deleted file mode 100644 index c6e4e13718..0000000000 --- a/svelte-keymap/src/components/editor/examples/keymap/editor.svelte +++ /dev/null @@ -1,43 +0,0 @@ - - - -
- -
-
-
-
-
- Submit Records -
    - {#each submissions as submission, index (index)} -
  1. -
    {submission}
    -
  2. - {/each} -
- {#if submissions.length === 0} -
No submissions yet
- {/if} -
-
diff --git a/svelte-keymap/src/components/editor/examples/keymap/extension.ts b/svelte-keymap/src/components/editor/examples/keymap/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/svelte-keymap/src/components/editor/examples/keymap/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/svelte-keymap/src/components/editor/examples/keymap/index.ts b/svelte-keymap/src/components/editor/examples/keymap/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-keymap/src/components/editor/examples/keymap/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-keymap/src/components/editor/examples/keymap/toolbar.svelte b/svelte-keymap/src/components/editor/examples/keymap/toolbar.svelte deleted file mode 100644 index 248e0deb50..0000000000 --- a/svelte-keymap/src/components/editor/examples/keymap/toolbar.svelte +++ /dev/null @@ -1,45 +0,0 @@ - - -
- - - -
diff --git a/svelte-keymap/src/components/editor/ui/button/button.svelte b/svelte-keymap/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-keymap/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-keymap/src/components/editor/ui/button/index.ts b/svelte-keymap/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-keymap/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-keymap/src/main.ts b/svelte-keymap/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-keymap/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-keymap/src/vite-env.d.ts b/svelte-keymap/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-keymap/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-keymap/svelte.config.js b/svelte-keymap/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-keymap/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-keymap/tsconfig.json b/svelte-keymap/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-keymap/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-keymap/tsconfig.node.json b/svelte-keymap/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-keymap/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-keymap/vite.config.ts b/svelte-keymap/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-keymap/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-link-mark-view/.gitignore b/svelte-link-mark-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-link-mark-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-link-mark-view/README.md b/svelte-link-mark-view/README.md deleted file mode 100644 index 59aadd7f51..0000000000 --- a/svelte-link-mark-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-link-mark-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-link-mark-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-link-mark-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-link-mark-view svelte-link-mark-view -cd svelte-link-mark-view -npm install -npm run dev -``` diff --git a/svelte-link-mark-view/index.html b/svelte-link-mark-view/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-link-mark-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-link-mark-view/package.json b/svelte-link-mark-view/package.json deleted file mode 100644 index e22c81bf85..0000000000 --- a/svelte-link-mark-view/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-link-mark-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-link-mark-view/src/App.svelte b/svelte-link-mark-view/src/App.svelte deleted file mode 100644 index 84ff419f29..0000000000 --- a/svelte-link-mark-view/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-link-mark-view/src/app.css b/svelte-link-mark-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-link-mark-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/editor.svelte b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/editor.svelte deleted file mode 100644 index b6efd2c7f7..0000000000 --- a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/editor.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts deleted file mode 100644 index 93e37e9334..0000000000 --- a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineSvelteMarkView } from 'prosekit/svelte' - -import LinkView from './link-view.svelte' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineSvelteMarkView({ - name: 'link', - component: LinkView, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/link-view.svelte b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/link-view.svelte deleted file mode 100644 index 9aea6240ff..0000000000 --- a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/link-view.svelte +++ /dev/null @@ -1,50 +0,0 @@ - - - - diff --git a/svelte-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/svelte-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts deleted file mode 100644 index 57abd09dd6..0000000000 --- a/svelte-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is a link that changes color every second: ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/svelte-link-mark-view/src/main.ts b/svelte-link-mark-view/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-link-mark-view/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-link-mark-view/src/vite-env.d.ts b/svelte-link-mark-view/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-link-mark-view/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-link-mark-view/svelte.config.js b/svelte-link-mark-view/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-link-mark-view/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-link-mark-view/tsconfig.json b/svelte-link-mark-view/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-link-mark-view/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-link-mark-view/tsconfig.node.json b/svelte-link-mark-view/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-link-mark-view/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-link-mark-view/vite.config.ts b/svelte-link-mark-view/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-link-mark-view/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-link/.gitignore b/svelte-link/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-link/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-link/README.md b/svelte-link/README.md deleted file mode 100644 index 0f32085730..0000000000 --- a/svelte-link/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-link - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-link) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-link) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-link svelte-link -cd svelte-link -npm install -npm run dev -``` diff --git a/svelte-link/index.html b/svelte-link/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-link/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-link/package.json b/svelte-link/package.json deleted file mode 100644 index 6db5d4fd39..0000000000 --- a/svelte-link/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-link", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-link/src/App.svelte b/svelte-link/src/App.svelte deleted file mode 100644 index 1ad5cdd8dd..0000000000 --- a/svelte-link/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-link/src/app.css b/svelte-link/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-link/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-link/src/components/editor/examples/link/editor.svelte b/svelte-link/src/components/editor/examples/link/editor.svelte deleted file mode 100644 index 92d4a9816c..0000000000 --- a/svelte-link/src/components/editor/examples/link/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
-
-
- -
-
-
diff --git a/svelte-link/src/components/editor/examples/link/extension.ts b/svelte-link/src/components/editor/examples/link/extension.ts deleted file mode 100644 index bf499147da..0000000000 --- a/svelte-link/src/components/editor/examples/link/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLink } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-link/src/components/editor/examples/link/index.ts b/svelte-link/src/components/editor/examples/link/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-link/src/components/editor/examples/link/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-link/src/components/editor/sample/sample-doc-link.ts b/svelte-link/src/components/editor/sample/sample-doc-link.ts deleted file mode 100644 index 726cf334fd..0000000000 --- a/svelte-link/src/components/editor/sample/sample-doc-link.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is an ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/svelte-link/src/components/editor/ui/button/button.svelte b/svelte-link/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-link/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-link/src/components/editor/ui/button/index.ts b/svelte-link/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-link/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-link/src/components/editor/ui/inline-menu/index.ts b/svelte-link/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index bf78dd2139..0000000000 --- a/svelte-link/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-link/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-link/src/components/editor/ui/inline-menu/inline-menu.svelte deleted file mode 100644 index 989f0c013b..0000000000 --- a/svelte-link/src/components/editor/ui/inline-menu/inline-menu.svelte +++ /dev/null @@ -1,207 +0,0 @@ - - - { - if (!event.detail) linkMenuOpen = false - }} -> - - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.link?.canExec && $items.link} - - {/if} - - - - - { - linkMenuOpen = event.detail - }} -> - - - {#if linkMenuOpen && $items.link} -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- {/if} - {#if $items.link?.isActive} - - {/if} -
-
-
diff --git a/svelte-link/src/main.ts b/svelte-link/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-link/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-link/src/vite-env.d.ts b/svelte-link/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-link/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-link/svelte.config.js b/svelte-link/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-link/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-link/tsconfig.json b/svelte-link/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-link/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-link/tsconfig.node.json b/svelte-link/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-link/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-link/vite.config.ts b/svelte-link/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-link/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-list-custom-checkbox/.gitignore b/svelte-list-custom-checkbox/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-list-custom-checkbox/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-list-custom-checkbox/README.md b/svelte-list-custom-checkbox/README.md deleted file mode 100644 index 760db805cb..0000000000 --- a/svelte-list-custom-checkbox/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-list-custom-checkbox - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-list-custom-checkbox) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-list-custom-checkbox) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-list-custom-checkbox svelte-list-custom-checkbox -cd svelte-list-custom-checkbox -npm install -npm run dev -``` diff --git a/svelte-list-custom-checkbox/index.html b/svelte-list-custom-checkbox/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-list-custom-checkbox/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-list-custom-checkbox/package.json b/svelte-list-custom-checkbox/package.json deleted file mode 100644 index 72e6946775..0000000000 --- a/svelte-list-custom-checkbox/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-list-custom-checkbox", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-list-custom-checkbox/src/App.svelte b/svelte-list-custom-checkbox/src/App.svelte deleted file mode 100644 index 408fa4ea3f..0000000000 --- a/svelte-list-custom-checkbox/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-list-custom-checkbox/src/app.css b/svelte-list-custom-checkbox/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-list-custom-checkbox/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css deleted file mode 100644 index ec631b72ad..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css +++ /dev/null @@ -1,75 +0,0 @@ -div[data-custom-list-css-enabled] - .ProseMirror - .prosemirror-flat-list[data-list-kind='task'] { - & > .list-marker label { - box-sizing: border-box; - display: flex; - position: relative; - left: calc(var(--spacing) * -0.5); - align-items: center; - cursor: pointer; - transition: transform 0.15s ease-in-out; - - &:hover { - transform: scale(1.1); - } - - &::after { - position: absolute; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - content: ''; - color: var(--color-white); - opacity: 0; - } - - /* https://api.iconify.design/lucide.css?icons=check */ - &::after { - display: inline-block; - background-color: currentColor; - -webkit-mask-image: var(--svg); - mask-image: var(--svg); - -webkit-mask-repeat: no-repeat; - mask-repeat: no-repeat; - -webkit-mask-size: 100% 100%; - mask-size: 100% 100%; - --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); - } - - & input { - box-sizing: border-box; - appearance: none; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - margin: 0; - border-width: 1px; - border-style: solid; - border-radius: var(--radius-md); - border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); - box-shadow: var(--shadow-sm); - cursor: pointer; - transition: all 0.15s ease-in-out; - - &:hover { - box-shadow: var(--shadow-md); - } - - &:checked { - border-color: var(--color-red-500); - background-color: var(--color-red-500); - } - } - } - - &[data-list-checked] > .list-marker label { - &::after { - opacity: 1; - } - } - - &[data-list-checked] { - color: var(--color-gray-400); - text-decoration: line-through; - text-decoration-color: var(--color-gray-400); - } -} diff --git a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.svelte b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.svelte deleted file mode 100644 index d0cc93914f..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.svelte +++ /dev/null @@ -1,31 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/svelte-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts deleted file mode 100644 index 972611aed1..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', - }, - { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, - { type: 'text', text: ' for the styles.' }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Completed Task' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Incomplete Task' }], - }, - ], - }, - ], -} diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/button/button.svelte b/svelte-list-custom-checkbox/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/button/index.ts b/svelte-list-custom-checkbox/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-list-custom-checkbox/src/main.ts b/svelte-list-custom-checkbox/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-list-custom-checkbox/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-list-custom-checkbox/src/vite-env.d.ts b/svelte-list-custom-checkbox/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-list-custom-checkbox/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-list-custom-checkbox/svelte.config.js b/svelte-list-custom-checkbox/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-list-custom-checkbox/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-list-custom-checkbox/tsconfig.json b/svelte-list-custom-checkbox/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-list-custom-checkbox/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-list-custom-checkbox/tsconfig.node.json b/svelte-list-custom-checkbox/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-list-custom-checkbox/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-list-custom-checkbox/vite.config.ts b/svelte-list-custom-checkbox/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-list-custom-checkbox/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-list/.gitignore b/svelte-list/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-list/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-list/README.md b/svelte-list/README.md deleted file mode 100644 index f943199072..0000000000 --- a/svelte-list/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-list - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-list) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-list) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-list svelte-list -cd svelte-list -npm install -npm run dev -``` diff --git a/svelte-list/index.html b/svelte-list/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-list/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-list/package.json b/svelte-list/package.json deleted file mode 100644 index 30b01a2ef6..0000000000 --- a/svelte-list/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-list", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-list/src/App.svelte b/svelte-list/src/App.svelte deleted file mode 100644 index 540d0595d0..0000000000 --- a/svelte-list/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-list/src/app.css b/svelte-list/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-list/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-list/src/components/editor/examples/list/editor.svelte b/svelte-list/src/components/editor/examples/list/editor.svelte deleted file mode 100644 index f148dbea23..0000000000 --- a/svelte-list/src/components/editor/examples/list/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-list/src/components/editor/examples/list/extension.ts b/svelte-list/src/components/editor/examples/list/extension.ts deleted file mode 100644 index f66bae6ff7..0000000000 --- a/svelte-list/src/components/editor/examples/list/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineList } from 'prosekit/extensions/list' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineList(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-list/src/components/editor/examples/list/index.ts b/svelte-list/src/components/editor/examples/list/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-list/src/components/editor/examples/list/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-list/src/components/editor/sample/sample-doc-list.ts b/svelte-list/src/components/editor/sample/sample-doc-list.ts deleted file mode 100644 index 091bc37185..0000000000 --- a/svelte-list/src/components/editor/sample/sample-doc-list.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Ordered List' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'toggle', collapsed: true }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, - { - type: 'list', - attrs: { - kind: 'bullet', - }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, - ], - }, - ], - }, - ], -} diff --git a/svelte-list/src/components/editor/ui/button/button.svelte b/svelte-list/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-list/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-list/src/components/editor/ui/button/index.ts b/svelte-list/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-list/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-list/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-list/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-list/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-list/src/components/editor/ui/image-upload-popover/index.ts b/svelte-list/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-list/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-list/src/components/editor/ui/toolbar/index.ts b/svelte-list/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-list/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-list/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-list/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-list/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-list/src/main.ts b/svelte-list/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-list/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-list/src/vite-env.d.ts b/svelte-list/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-list/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-list/svelte.config.js b/svelte-list/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-list/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-list/tsconfig.json b/svelte-list/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-list/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-list/tsconfig.node.json b/svelte-list/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-list/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-list/vite.config.ts b/svelte-list/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-list/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-loro/.gitignore b/svelte-loro/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-loro/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-loro/README.md b/svelte-loro/README.md deleted file mode 100644 index 01b4624a76..0000000000 --- a/svelte-loro/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-loro - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-loro) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-loro) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-loro svelte-loro -cd svelte-loro -npm install -npm run dev -``` diff --git a/svelte-loro/index.html b/svelte-loro/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-loro/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-loro/package.json b/svelte-loro/package.json deleted file mode 100644 index 87ac5ac4ad..0000000000 --- a/svelte-loro/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "example-svelte-loro", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "loro-crdt": "^1.12.1", - "loro-prosemirror": "^0.4.3", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-wasm": "^3.6.0" - } -} diff --git a/svelte-loro/src/App.svelte b/svelte-loro/src/App.svelte deleted file mode 100644 index e1c0eb1713..0000000000 --- a/svelte-loro/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-loro/src/app.css b/svelte-loro/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-loro/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-loro/src/components/editor/examples/loro/editor-component.svelte b/svelte-loro/src/components/editor/examples/loro/editor-component.svelte deleted file mode 100644 index 7d5be7ece2..0000000000 --- a/svelte-loro/src/components/editor/examples/loro/editor-component.svelte +++ /dev/null @@ -1,32 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-loro/src/components/editor/examples/loro/editor.svelte b/svelte-loro/src/components/editor/examples/loro/editor.svelte deleted file mode 100644 index 0086564202..0000000000 --- a/svelte-loro/src/components/editor/examples/loro/editor.svelte +++ /dev/null @@ -1,55 +0,0 @@ - - -
- - -
diff --git a/svelte-loro/src/components/editor/examples/loro/extension.ts b/svelte-loro/src/components/editor/examples/loro/extension.ts deleted file mode 100644 index 5b2380c7c9..0000000000 --- a/svelte-loro/src/components/editor/examples/loro/extension.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineLoro } from 'prosekit/extensions/loro' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { - return union( - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineLoro({ doc, awareness }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-loro/src/components/editor/examples/loro/index.ts b/svelte-loro/src/components/editor/examples/loro/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-loro/src/components/editor/examples/loro/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-loro/src/components/editor/ui/button/button.svelte b/svelte-loro/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-loro/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-loro/src/components/editor/ui/button/index.ts b/svelte-loro/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-loro/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-loro/src/components/editor/ui/image-upload-popover/index.ts b/svelte-loro/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-loro/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-loro/src/components/editor/ui/toolbar/index.ts b/svelte-loro/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-loro/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-loro/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-loro/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-loro/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-loro/src/main.ts b/svelte-loro/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-loro/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-loro/src/vite-env.d.ts b/svelte-loro/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-loro/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-loro/svelte.config.js b/svelte-loro/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-loro/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-loro/tsconfig.json b/svelte-loro/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-loro/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-loro/tsconfig.node.json b/svelte-loro/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-loro/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-loro/vite.config.ts b/svelte-loro/vite.config.ts deleted file mode 100644 index d4fb669e14..0000000000 --- a/svelte-loro/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import wasm from 'vite-plugin-wasm' -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [wasm(), svelte(), tailwindcss()], -}) diff --git a/svelte-mark-rule/.gitignore b/svelte-mark-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-mark-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-mark-rule/README.md b/svelte-mark-rule/README.md deleted file mode 100644 index 243502eb29..0000000000 --- a/svelte-mark-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-mark-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-mark-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-mark-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-mark-rule svelte-mark-rule -cd svelte-mark-rule -npm install -npm run dev -``` diff --git a/svelte-mark-rule/index.html b/svelte-mark-rule/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-mark-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-mark-rule/package.json b/svelte-mark-rule/package.json deleted file mode 100644 index 7bab92ccff..0000000000 --- a/svelte-mark-rule/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-mark-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-mark-rule/src/App.svelte b/svelte-mark-rule/src/App.svelte deleted file mode 100644 index 2d590088e8..0000000000 --- a/svelte-mark-rule/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-mark-rule/src/app.css b/svelte-mark-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-mark-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-mark-rule/src/components/editor/examples/mark-rule/editor.svelte b/svelte-mark-rule/src/components/editor/examples/mark-rule/editor.svelte deleted file mode 100644 index 03b6c9f2ca..0000000000 --- a/svelte-mark-rule/src/components/editor/examples/mark-rule/editor.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/svelte-mark-rule/src/components/editor/examples/mark-rule/extension.ts deleted file mode 100644 index 4a1de40783..0000000000 --- a/svelte-mark-rule/src/components/editor/examples/mark-rule/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - defineBaseCommands, - defineBaseKeymap, - defineHistory, - union, -} from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { definePlaceholder } from 'prosekit/extensions/placeholder' -import { defineText } from 'prosekit/extensions/text' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -import { defineIssueLink } from './issue-link' - -export function defineExtension() { - return union( - defineDoc(), - defineText(), - defineParagraph(), - defineHistory(), - defineBaseKeymap(), - defineBaseCommands(), - defineVirtualSelection(), - defineLinkSpec(), - defineLinkMarkRule(), - definePlaceholder({ placeholder: 'Try typing #123' }), - defineIssueLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-mark-rule/src/components/editor/examples/mark-rule/index.ts b/svelte-mark-rule/src/components/editor/examples/mark-rule/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-mark-rule/src/components/editor/examples/mark-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/svelte-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts deleted file mode 100644 index 3840b5e53d..0000000000 --- a/svelte-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { defineMarkSpec, union } from 'prosekit/core' -import { defineMarkRule } from 'prosekit/extensions/mark-rule' - -export function defineIssueLink() { - return union( - defineMarkSpec({ - name: 'issueLink', - inclusive: false, - attrs: { - issueNumber: {}, - }, - toDOM(node) { - const issueNumber = node.attrs.issueNumber as number - return [ - 'a', - { - href: `https://example.com/issues/${issueNumber}`, - title: `Issue #${issueNumber}`, - }, - 0, - ] - }, - }), - defineMarkRule({ - regex: /#(\d+)/g, - type: 'issueLink', - attrs: (match) => { - return { issueNumber: Number.parseInt(match[1] || '0') } - }, - }), - ) -} diff --git a/svelte-mark-rule/src/main.ts b/svelte-mark-rule/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-mark-rule/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-mark-rule/src/vite-env.d.ts b/svelte-mark-rule/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-mark-rule/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-mark-rule/svelte.config.js b/svelte-mark-rule/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-mark-rule/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-mark-rule/tsconfig.json b/svelte-mark-rule/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-mark-rule/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-mark-rule/tsconfig.node.json b/svelte-mark-rule/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-mark-rule/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-mark-rule/vite.config.ts b/svelte-mark-rule/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-mark-rule/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-minimal/.gitignore b/svelte-minimal/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-minimal/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-minimal/README.md b/svelte-minimal/README.md deleted file mode 100644 index d212c5f932..0000000000 --- a/svelte-minimal/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-minimal - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-minimal) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-minimal) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-minimal svelte-minimal -cd svelte-minimal -npm install -npm run dev -``` diff --git a/svelte-minimal/index.html b/svelte-minimal/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-minimal/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-minimal/package.json b/svelte-minimal/package.json deleted file mode 100644 index 926aa495b8..0000000000 --- a/svelte-minimal/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-minimal", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-minimal/src/App.svelte b/svelte-minimal/src/App.svelte deleted file mode 100644 index e4e92350bf..0000000000 --- a/svelte-minimal/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-minimal/src/app.css b/svelte-minimal/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-minimal/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-minimal/src/components/editor/examples/minimal/editor.svelte b/svelte-minimal/src/components/editor/examples/minimal/editor.svelte deleted file mode 100644 index 10f7602cb4..0000000000 --- a/svelte-minimal/src/components/editor/examples/minimal/editor.svelte +++ /dev/null @@ -1,15 +0,0 @@ - - - -
-
diff --git a/svelte-minimal/src/components/editor/examples/minimal/index.ts b/svelte-minimal/src/components/editor/examples/minimal/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-minimal/src/components/editor/examples/minimal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-minimal/src/main.ts b/svelte-minimal/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-minimal/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-minimal/src/vite-env.d.ts b/svelte-minimal/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-minimal/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-minimal/svelte.config.js b/svelte-minimal/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-minimal/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-minimal/tsconfig.json b/svelte-minimal/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-minimal/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-minimal/tsconfig.node.json b/svelte-minimal/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-minimal/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-minimal/vite.config.ts b/svelte-minimal/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-minimal/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-page/.gitignore b/svelte-page/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-page/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-page/README.md b/svelte-page/README.md deleted file mode 100644 index 7a3acaae74..0000000000 --- a/svelte-page/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-page - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-page) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-page) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-page svelte-page -cd svelte-page -npm install -npm run dev -``` diff --git a/svelte-page/index.html b/svelte-page/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-page/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-page/package.json b/svelte-page/package.json deleted file mode 100644 index dd67b1d8ac..0000000000 --- a/svelte-page/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-page", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-page/src/App.svelte b/svelte-page/src/App.svelte deleted file mode 100644 index a6ae83118a..0000000000 --- a/svelte-page/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-page/src/app.css b/svelte-page/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-page/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-page/src/components/editor/examples/page/editor.svelte b/svelte-page/src/components/editor/examples/page/editor.svelte deleted file mode 100644 index 258fa08c71..0000000000 --- a/svelte-page/src/components/editor/examples/page/editor.svelte +++ /dev/null @@ -1,38 +0,0 @@ - - - -
- -
-
-
-
diff --git a/svelte-page/src/components/editor/examples/page/extension.ts b/svelte-page/src/components/editor/examples/page/extension.ts deleted file mode 100644 index edf01e897b..0000000000 --- a/svelte-page/src/components/editor/examples/page/extension.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePageBreak } from 'prosekit/extensions/page' - -export function defineExtension() { - return union(defineBasicExtension(), definePageBreak()) -} - -export type EditorExtension = ReturnType diff --git a/svelte-page/src/components/editor/examples/page/index.ts b/svelte-page/src/components/editor/examples/page/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-page/src/components/editor/examples/page/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-page/src/components/editor/examples/page/paper-controller.svelte b/svelte-page/src/components/editor/examples/page/paper-controller.svelte deleted file mode 100644 index f62022f2b6..0000000000 --- a/svelte-page/src/components/editor/examples/page/paper-controller.svelte +++ /dev/null @@ -1,143 +0,0 @@ - - -
- - - - - - - - - - -
diff --git a/svelte-page/src/components/editor/examples/page/zoom.css b/svelte-page/src/components/editor/examples/page/zoom.css deleted file mode 100644 index bd81302639..0000000000 --- a/svelte-page/src/components/editor/examples/page/zoom.css +++ /dev/null @@ -1,9 +0,0 @@ -div[data-editor-zoom] { - zoom: var(--zoom); -} - -@media print { - div[data-editor-zoom] { - zoom: 1; - } -} diff --git a/svelte-page/src/components/editor/sample/sample-doc-page.ts b/svelte-page/src/components/editor/sample/sample-doc-page.ts deleted file mode 100644 index 60e78ac18e..0000000000 --- a/svelte-page/src/components/editor/sample/sample-doc-page.ts +++ /dev/null @@ -1,98 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Page Layout Demo' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is the first page.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The content below will be on a new page because of a page break. You can insert a page break by pressing Command+Enter on Mac or Ctrl+Enter on Windows and Linux.', - }, - ], - }, - { type: 'pageBreak' }, - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Page 2' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is the second page.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'When the content on a page exceeds the available height, it will automatically flow to the next page. This is similar to how traditional word processors like Microsoft Word handle pagination.', - }, - ], - }, - { type: 'image', attrs: { src: 'https://placehold.co/600x500' } }, - { type: 'image', attrs: { src: 'https://placehold.co/600x500' } }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The images above exceed the available height on the second page, so they automatically flow to the next page.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Known Limitation' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Page breaks only occur between block elements. A single block taller than the remaining space on the page will overflow to the next page rather than split. In other words, you cannot split a node like paragraph or a table across pages. The paragraph below demonstrates this.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'This is a very long paragraph that demonstrates the limitation of block-level pagination.', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [{ type: 'italic' }], - text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.', - }, - ], - }, - ], -} diff --git a/svelte-page/src/main.ts b/svelte-page/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-page/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-page/src/vite-env.d.ts b/svelte-page/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-page/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-page/svelte.config.js b/svelte-page/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-page/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-page/tsconfig.json b/svelte-page/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-page/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-page/tsconfig.node.json b/svelte-page/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-page/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-page/vite.config.ts b/svelte-page/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-page/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-placeholder/.gitignore b/svelte-placeholder/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-placeholder/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-placeholder/README.md b/svelte-placeholder/README.md deleted file mode 100644 index bbdab9669b..0000000000 --- a/svelte-placeholder/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-placeholder - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-placeholder) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-placeholder) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-placeholder svelte-placeholder -cd svelte-placeholder -npm install -npm run dev -``` diff --git a/svelte-placeholder/index.html b/svelte-placeholder/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-placeholder/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-placeholder/package.json b/svelte-placeholder/package.json deleted file mode 100644 index 616909d3cc..0000000000 --- a/svelte-placeholder/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-placeholder", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-placeholder/src/App.svelte b/svelte-placeholder/src/App.svelte deleted file mode 100644 index daf201f559..0000000000 --- a/svelte-placeholder/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-placeholder/src/app.css b/svelte-placeholder/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-placeholder/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-placeholder/src/components/editor/examples/placeholder/editor.svelte b/svelte-placeholder/src/components/editor/examples/placeholder/editor.svelte deleted file mode 100644 index 3cfe679b52..0000000000 --- a/svelte-placeholder/src/components/editor/examples/placeholder/editor.svelte +++ /dev/null @@ -1,31 +0,0 @@ - - - -
-
-
-
-
-
diff --git a/svelte-placeholder/src/components/editor/examples/placeholder/extension.ts b/svelte-placeholder/src/components/editor/examples/placeholder/extension.ts deleted file mode 100644 index 12d0ba26f4..0000000000 --- a/svelte-placeholder/src/components/editor/examples/placeholder/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Type something...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-placeholder/src/components/editor/examples/placeholder/index.ts b/svelte-placeholder/src/components/editor/examples/placeholder/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-placeholder/src/components/editor/examples/placeholder/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-placeholder/src/main.ts b/svelte-placeholder/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-placeholder/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-placeholder/src/vite-env.d.ts b/svelte-placeholder/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-placeholder/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-placeholder/svelte.config.js b/svelte-placeholder/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-placeholder/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-placeholder/tsconfig.json b/svelte-placeholder/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-placeholder/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-placeholder/tsconfig.node.json b/svelte-placeholder/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-placeholder/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-placeholder/vite.config.ts b/svelte-placeholder/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-placeholder/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-readonly/.gitignore b/svelte-readonly/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-readonly/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-readonly/README.md b/svelte-readonly/README.md deleted file mode 100644 index df4ef2e36c..0000000000 --- a/svelte-readonly/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-readonly - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-readonly) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-readonly) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-readonly svelte-readonly -cd svelte-readonly -npm install -npm run dev -``` diff --git a/svelte-readonly/index.html b/svelte-readonly/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-readonly/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-readonly/package.json b/svelte-readonly/package.json deleted file mode 100644 index 2c5e0e5fee..0000000000 --- a/svelte-readonly/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-readonly", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-readonly/src/App.svelte b/svelte-readonly/src/App.svelte deleted file mode 100644 index 969fdf2360..0000000000 --- a/svelte-readonly/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-readonly/src/app.css b/svelte-readonly/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-readonly/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-readonly/src/components/editor/examples/readonly/editor.svelte b/svelte-readonly/src/components/editor/examples/readonly/editor.svelte deleted file mode 100644 index 1bee26c40a..0000000000 --- a/svelte-readonly/src/components/editor/examples/readonly/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-readonly/src/components/editor/examples/readonly/extension.ts b/svelte-readonly/src/components/editor/examples/readonly/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/svelte-readonly/src/components/editor/examples/readonly/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/svelte-readonly/src/components/editor/examples/readonly/index.ts b/svelte-readonly/src/components/editor/examples/readonly/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-readonly/src/components/editor/examples/readonly/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-readonly/src/components/editor/examples/readonly/toolbar.svelte b/svelte-readonly/src/components/editor/examples/readonly/toolbar.svelte deleted file mode 100644 index bbec4e4f76..0000000000 --- a/svelte-readonly/src/components/editor/examples/readonly/toolbar.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - -
- - - -
diff --git a/svelte-readonly/src/components/editor/sample/sample-doc-readonly.ts b/svelte-readonly/src/components/editor/sample/sample-doc-readonly.ts deleted file mode 100644 index abd9e2c6ac..0000000000 --- a/svelte-readonly/src/components/editor/sample/sample-doc-readonly.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', - }, - ], - }, - ], -} diff --git a/svelte-readonly/src/components/editor/ui/button/button.svelte b/svelte-readonly/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-readonly/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-readonly/src/components/editor/ui/button/index.ts b/svelte-readonly/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-readonly/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-readonly/src/main.ts b/svelte-readonly/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-readonly/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-readonly/src/vite-env.d.ts b/svelte-readonly/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-readonly/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-readonly/svelte.config.js b/svelte-readonly/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-readonly/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-readonly/tsconfig.json b/svelte-readonly/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-readonly/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-readonly/tsconfig.node.json b/svelte-readonly/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-readonly/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-readonly/vite.config.ts b/svelte-readonly/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-readonly/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-rtl/.gitignore b/svelte-rtl/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-rtl/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-rtl/README.md b/svelte-rtl/README.md deleted file mode 100644 index 818025e82b..0000000000 --- a/svelte-rtl/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-rtl - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-rtl) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-rtl) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-rtl svelte-rtl -cd svelte-rtl -npm install -npm run dev -``` diff --git a/svelte-rtl/index.html b/svelte-rtl/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-rtl/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-rtl/package.json b/svelte-rtl/package.json deleted file mode 100644 index 8a20110c06..0000000000 --- a/svelte-rtl/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-rtl", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-rtl/src/App.svelte b/svelte-rtl/src/App.svelte deleted file mode 100644 index 96c115496b..0000000000 --- a/svelte-rtl/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-rtl/src/app.css b/svelte-rtl/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-rtl/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-rtl/src/components/editor/examples/rtl/editor.svelte b/svelte-rtl/src/components/editor/examples/rtl/editor.svelte deleted file mode 100644 index a1ecfd2377..0000000000 --- a/svelte-rtl/src/components/editor/examples/rtl/editor.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - -
- -
-
- - - - - -
-
-
diff --git a/svelte-rtl/src/components/editor/examples/rtl/index.ts b/svelte-rtl/src/components/editor/examples/rtl/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-rtl/src/components/editor/examples/rtl/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-rtl/src/components/editor/sample/sample-doc-rtl.ts b/svelte-rtl/src/components/editor/sample/sample-doc-rtl.ts deleted file mode 100644 index 696e797724..0000000000 --- a/svelte-rtl/src/components/editor/sample/sample-doc-rtl.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const translation = { - Paragraph: 'فقرة', - 'Root list item': 'عنصر قائمة جذري', - 'Sub list item': 'عنصر قائمة فرعي', - 'Completed task': 'مهمة مكتملة', - 'Pending task': 'مهمة قيد الانتظار', - Quote: 'اقتباس', -} as const - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Right to Left' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Paragraph'] }], - }, - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Root list item'] }], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Completed task'] }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Pending task'] }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: 'hello world', - }, - ], - }, - - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, - ], - }, - ], - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: translation['Quote'], - }, - ], - }, - ], - }, - ], -} diff --git a/svelte-rtl/src/components/editor/sample/sample-uploader.ts b/svelte-rtl/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/svelte-rtl/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/svelte-rtl/src/components/editor/ui/block-handle/block-handle.svelte b/svelte-rtl/src/components/editor/ui/block-handle/block-handle.svelte deleted file mode 100644 index f67e42dc91..0000000000 --- a/svelte-rtl/src/components/editor/ui/block-handle/block-handle.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - -
-
- -
-
-
-
-
diff --git a/svelte-rtl/src/components/editor/ui/block-handle/index.ts b/svelte-rtl/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 6d21191384..0000000000 --- a/svelte-rtl/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.svelte' diff --git a/svelte-rtl/src/components/editor/ui/button/button.svelte b/svelte-rtl/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-rtl/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-rtl/src/components/editor/ui/button/index.ts b/svelte-rtl/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-rtl/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-rtl/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/svelte-rtl/src/components/editor/ui/drop-indicator/drop-indicator.svelte deleted file mode 100644 index 7f6cac1db0..0000000000 --- a/svelte-rtl/src/components/editor/ui/drop-indicator/drop-indicator.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-rtl/src/components/editor/ui/drop-indicator/index.ts b/svelte-rtl/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index 06e89357ed..0000000000 --- a/svelte-rtl/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator.svelte' diff --git a/svelte-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-rtl/src/components/editor/ui/image-upload-popover/index.ts b/svelte-rtl/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-rtl/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-rtl/src/components/editor/ui/inline-menu/index.ts b/svelte-rtl/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index bf78dd2139..0000000000 --- a/svelte-rtl/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-rtl/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-rtl/src/components/editor/ui/inline-menu/inline-menu.svelte deleted file mode 100644 index 989f0c013b..0000000000 --- a/svelte-rtl/src/components/editor/ui/inline-menu/inline-menu.svelte +++ /dev/null @@ -1,207 +0,0 @@ - - - { - if (!event.detail) linkMenuOpen = false - }} -> - - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.link?.canExec && $items.link} - - {/if} - - - - - { - linkMenuOpen = event.detail - }} -> - - - {#if linkMenuOpen && $items.link} -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- {/if} - {#if $items.link?.isActive} - - {/if} -
-
-
diff --git a/svelte-rtl/src/components/editor/ui/slash-menu/index.ts b/svelte-rtl/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 856d4e6b43..0000000000 --- a/svelte-rtl/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu.svelte' diff --git a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.svelte b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.svelte deleted file mode 100644 index 37cea8de67..0000000000 --- a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - - No results - diff --git a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-item.svelte b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-item.svelte deleted file mode 100644 index 52126eeb68..0000000000 --- a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-item.svelte +++ /dev/null @@ -1,15 +0,0 @@ - - - - {props.label}{#if props.kbd}{props.kbd}{/if} - diff --git a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu.svelte b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu.svelte deleted file mode 100644 index 5da516b44f..0000000000 --- a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu.svelte +++ /dev/null @@ -1,94 +0,0 @@ - - - - - -
- $editor.commands.setParagraph()} - /> - - $editor.commands.setHeading({ level: 1 })} - /> - - $editor.commands.setHeading({ level: 2 })} - /> - - $editor.commands.setHeading({ level: 3 })} - /> - - $editor.commands.wrapInList({ kind: 'bullet' })} - /> - - $editor.commands.wrapInList({ kind: 'ordered' })} - /> - - $editor.commands.wrapInList({ kind: 'task' })} - /> - - $editor.commands.wrapInList({ kind: 'toggle' })} - /> - - $editor.commands.setBlockquote()} - /> - - $editor.commands.insertTable({ row: 3, col: 3 })} - /> - - $editor.commands.insertHorizontalRule()} - /> - - $editor.commands.setCodeBlock()} - /> - - -
-
-
-
diff --git a/svelte-rtl/src/components/editor/ui/table-handle/index.ts b/svelte-rtl/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 308cef59de..0000000000 --- a/svelte-rtl/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle.svelte' diff --git a/svelte-rtl/src/components/editor/ui/table-handle/table-handle.svelte b/svelte-rtl/src/components/editor/ui/table-handle/table-handle.svelte deleted file mode 100644 index fc91f9a438..0000000000 --- a/svelte-rtl/src/components/editor/ui/table-handle/table-handle.svelte +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - -
-
- - - {#if $state.addTableColumnBefore.canExec} - - Insert Left - - {/if} - {#if $state.addTableColumnAfter.canExec} - - Insert Right - - {/if} - {#if $state.deleteCellSelection.canExec} - - Clear Contents - Del - - {/if} - {#if $state.deleteTableColumn.canExec} - - Delete Column - - {/if} - {#if $state.deleteTable.canExec} - - Delete Table - - {/if} - - -
-
-
- - - - -
-
- - - {#if $state.addTableRowAbove.canExec} - - Insert Above - - {/if} - {#if $state.addTableRowBelow.canExec} - - Insert Below - - {/if} - {#if $state.deleteCellSelection.canExec} - - Clear Contents - Del - - {/if} - {#if $state.deleteTableRow.canExec} - - Delete Row - - {/if} - {#if $state.deleteTable.canExec} - - Delete Table - - {/if} - - -
-
-
-
diff --git a/svelte-rtl/src/components/editor/ui/toolbar/index.ts b/svelte-rtl/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-rtl/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-rtl/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-rtl/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-rtl/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-rtl/src/main.ts b/svelte-rtl/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-rtl/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-rtl/src/vite-env.d.ts b/svelte-rtl/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-rtl/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-rtl/svelte.config.js b/svelte-rtl/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-rtl/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-rtl/tsconfig.json b/svelte-rtl/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-rtl/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-rtl/tsconfig.node.json b/svelte-rtl/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-rtl/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-rtl/vite.config.ts b/svelte-rtl/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-rtl/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-save-html/.gitignore b/svelte-save-html/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-save-html/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-save-html/README.md b/svelte-save-html/README.md deleted file mode 100644 index 4519d57d39..0000000000 --- a/svelte-save-html/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-save-html - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-save-html) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-save-html) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-save-html svelte-save-html -cd svelte-save-html -npm install -npm run dev -``` diff --git a/svelte-save-html/index.html b/svelte-save-html/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-save-html/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-save-html/package.json b/svelte-save-html/package.json deleted file mode 100644 index 4092bd0530..0000000000 --- a/svelte-save-html/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-save-html", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-save-html/src/App.svelte b/svelte-save-html/src/App.svelte deleted file mode 100644 index 9505ae9dd8..0000000000 --- a/svelte-save-html/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-save-html/src/app.css b/svelte-save-html/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-save-html/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-save-html/src/components/editor/examples/save-html/editor.svelte b/svelte-save-html/src/components/editor/examples/save-html/editor.svelte deleted file mode 100644 index 6cab449c13..0000000000 --- a/svelte-save-html/src/components/editor/examples/save-html/editor.svelte +++ /dev/null @@ -1,67 +0,0 @@ - - -
- -
    - {#each records as record, index (index)} -
  • - - -
    {record}
    -
    -
  • - {/each} -
- {#key key} - -
-
-
-
- {/key} -
diff --git a/svelte-save-html/src/components/editor/examples/save-html/index.ts b/svelte-save-html/src/components/editor/examples/save-html/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-save-html/src/components/editor/examples/save-html/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-save-html/src/main.ts b/svelte-save-html/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-save-html/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-save-html/src/vite-env.d.ts b/svelte-save-html/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-save-html/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-save-html/svelte.config.js b/svelte-save-html/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-save-html/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-save-html/tsconfig.json b/svelte-save-html/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-save-html/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-save-html/tsconfig.node.json b/svelte-save-html/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-save-html/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-save-html/vite.config.ts b/svelte-save-html/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-save-html/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-save-json/.gitignore b/svelte-save-json/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-save-json/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-save-json/README.md b/svelte-save-json/README.md deleted file mode 100644 index 890e8c9c4d..0000000000 --- a/svelte-save-json/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-save-json - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-save-json) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-save-json) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-save-json svelte-save-json -cd svelte-save-json -npm install -npm run dev -``` diff --git a/svelte-save-json/index.html b/svelte-save-json/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-save-json/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-save-json/package.json b/svelte-save-json/package.json deleted file mode 100644 index 7513eeb4a9..0000000000 --- a/svelte-save-json/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-save-json", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-save-json/src/App.svelte b/svelte-save-json/src/App.svelte deleted file mode 100644 index 33dcb8119d..0000000000 --- a/svelte-save-json/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-save-json/src/app.css b/svelte-save-json/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-save-json/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-save-json/src/components/editor/examples/save-json/editor.svelte b/svelte-save-json/src/components/editor/examples/save-json/editor.svelte deleted file mode 100644 index 07d3415695..0000000000 --- a/svelte-save-json/src/components/editor/examples/save-json/editor.svelte +++ /dev/null @@ -1,67 +0,0 @@ - - -
- -
    - {#each records as record, index (index)} -
  • - - -
    {record}
    -
    -
  • - {/each} -
- {#key key} - -
-
-
-
- {/key} -
diff --git a/svelte-save-json/src/components/editor/examples/save-json/index.ts b/svelte-save-json/src/components/editor/examples/save-json/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-save-json/src/components/editor/examples/save-json/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-save-json/src/main.ts b/svelte-save-json/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-save-json/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-save-json/src/vite-env.d.ts b/svelte-save-json/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-save-json/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-save-json/svelte.config.js b/svelte-save-json/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-save-json/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-save-json/tsconfig.json b/svelte-save-json/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-save-json/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-save-json/tsconfig.node.json b/svelte-save-json/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-save-json/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-save-json/vite.config.ts b/svelte-save-json/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-save-json/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-save-markdown/.gitignore b/svelte-save-markdown/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-save-markdown/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-save-markdown/README.md b/svelte-save-markdown/README.md deleted file mode 100644 index 95ae1a77a4..0000000000 --- a/svelte-save-markdown/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-save-markdown - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-save-markdown) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-save-markdown) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-save-markdown svelte-save-markdown -cd svelte-save-markdown -npm install -npm run dev -``` diff --git a/svelte-save-markdown/index.html b/svelte-save-markdown/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-save-markdown/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-save-markdown/package.json b/svelte-save-markdown/package.json deleted file mode 100644 index 139486c273..0000000000 --- a/svelte-save-markdown/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "example-svelte-save-markdown", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "rehype-parse": "^9.0.1", - "rehype-remark": "^10.0.1", - "remark-gfm": "^4.0.1", - "remark-html": "^16.0.1", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.5" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-save-markdown/src/App.svelte b/svelte-save-markdown/src/App.svelte deleted file mode 100644 index cdcdeb67ba..0000000000 --- a/svelte-save-markdown/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-save-markdown/src/app.css b/svelte-save-markdown/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-save-markdown/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-save-markdown/src/components/editor/examples/save-markdown/editor.svelte b/svelte-save-markdown/src/components/editor/examples/save-markdown/editor.svelte deleted file mode 100644 index 79b78c9e1d..0000000000 --- a/svelte-save-markdown/src/components/editor/examples/save-markdown/editor.svelte +++ /dev/null @@ -1,71 +0,0 @@ - - -
- -
    - {#each records as record, index (index)} -
  • - - -
    {record}
    -
    -
  • - {/each} -
- {#key key} - -
-
-
-
- {/key} -
diff --git a/svelte-save-markdown/src/components/editor/examples/save-markdown/index.ts b/svelte-save-markdown/src/components/editor/examples/save-markdown/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-save-markdown/src/components/editor/examples/save-markdown/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/svelte-save-markdown/src/components/editor/examples/save-markdown/markdown.ts deleted file mode 100644 index 3f930adad2..0000000000 --- a/svelte-save-markdown/src/components/editor/examples/save-markdown/markdown.ts +++ /dev/null @@ -1,26 +0,0 @@ -import rehypeParse from 'rehype-parse' -import rehypeRemark from 'rehype-remark' -import remarkGfm from 'remark-gfm' -import remarkHtml from 'remark-html' -import remarkParse from 'remark-parse' -import remarkStringify from 'remark-stringify' -import { unified } from 'unified' - -export function markdownFromHTML(html: string): string { - return unified() - .use(rehypeParse) - .use(rehypeRemark) - .use(remarkGfm) - .use(remarkStringify) - .processSync(html) - .toString() -} - -export function htmlFromMarkdown(markdown: string): string { - return unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkHtml) - .processSync(markdown) - .toString() -} diff --git a/svelte-save-markdown/src/main.ts b/svelte-save-markdown/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-save-markdown/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-save-markdown/src/vite-env.d.ts b/svelte-save-markdown/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-save-markdown/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-save-markdown/svelte.config.js b/svelte-save-markdown/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-save-markdown/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-save-markdown/tsconfig.json b/svelte-save-markdown/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-save-markdown/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-save-markdown/tsconfig.node.json b/svelte-save-markdown/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-save-markdown/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-save-markdown/vite.config.ts b/svelte-save-markdown/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-save-markdown/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-search/.gitignore b/svelte-search/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-search/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-search/README.md b/svelte-search/README.md deleted file mode 100644 index a43a9f9b3a..0000000000 --- a/svelte-search/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-search - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-search) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-search) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-search svelte-search -cd svelte-search -npm install -npm run dev -``` diff --git a/svelte-search/index.html b/svelte-search/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-search/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-search/package.json b/svelte-search/package.json deleted file mode 100644 index 8014ed31e9..0000000000 --- a/svelte-search/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-search", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-search/src/App.svelte b/svelte-search/src/App.svelte deleted file mode 100644 index ab82613d74..0000000000 --- a/svelte-search/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-search/src/app.css b/svelte-search/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-search/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-search/src/components/editor/examples/search/editor.svelte b/svelte-search/src/components/editor/examples/search/editor.svelte deleted file mode 100644 index eb2ca32536..0000000000 --- a/svelte-search/src/components/editor/examples/search/editor.svelte +++ /dev/null @@ -1,31 +0,0 @@ - - - -
-
- -
-
-
-
diff --git a/svelte-search/src/components/editor/examples/search/extension.ts b/svelte-search/src/components/editor/examples/search/extension.ts deleted file mode 100644 index 10ff13f614..0000000000 --- a/svelte-search/src/components/editor/examples/search/extension.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineSearchCommands } from 'prosekit/extensions/search' - -export function defineExtension() { - return union(defineBasicExtension(), defineSearchCommands()) -} - -export type EditorExtension = ReturnType diff --git a/svelte-search/src/components/editor/examples/search/index.ts b/svelte-search/src/components/editor/examples/search/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-search/src/components/editor/examples/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-search/src/components/editor/sample/sample-doc-search.ts b/svelte-search/src/components/editor/sample/sample-doc-search.ts deleted file mode 100644 index c8160cca2a..0000000000 --- a/svelte-search/src/components/editor/sample/sample-doc-search.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Baa, baa, black sheep,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Have you any wool?', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Yes, sir, yes, sir,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Three bags full;', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'One for the master,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the dame,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the little boy', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Who lives down the lane.', - }, - ], - }, - ], -} diff --git a/svelte-search/src/components/editor/ui/button/button.svelte b/svelte-search/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-search/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-search/src/components/editor/ui/button/index.ts b/svelte-search/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-search/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-search/src/components/editor/ui/search/index.ts b/svelte-search/src/components/editor/ui/search/index.ts deleted file mode 100644 index 50dcb21701..0000000000 --- a/svelte-search/src/components/editor/ui/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Search } from './search.svelte' diff --git a/svelte-search/src/components/editor/ui/search/search.svelte b/svelte-search/src/components/editor/ui/search/search.svelte deleted file mode 100644 index 3daaa44de7..0000000000 --- a/svelte-search/src/components/editor/ui/search/search.svelte +++ /dev/null @@ -1,168 +0,0 @@ - - -
- - -
- - - - - - - -
- {#if showReplace} - -
- - -
- {/if} -
diff --git a/svelte-search/src/main.ts b/svelte-search/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-search/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-search/src/vite-env.d.ts b/svelte-search/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-search/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-search/svelte.config.js b/svelte-search/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-search/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-search/tsconfig.json b/svelte-search/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-search/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-search/tsconfig.node.json b/svelte-search/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-search/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-search/vite.config.ts b/svelte-search/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-search/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-slash-menu/.gitignore b/svelte-slash-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-slash-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-slash-menu/README.md b/svelte-slash-menu/README.md deleted file mode 100644 index 3c23fb3df4..0000000000 --- a/svelte-slash-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-slash-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-slash-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-slash-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-slash-menu svelte-slash-menu -cd svelte-slash-menu -npm install -npm run dev -``` diff --git a/svelte-slash-menu/index.html b/svelte-slash-menu/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-slash-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-slash-menu/package.json b/svelte-slash-menu/package.json deleted file mode 100644 index 8a6d27571d..0000000000 --- a/svelte-slash-menu/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-slash-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-slash-menu/src/App.svelte b/svelte-slash-menu/src/App.svelte deleted file mode 100644 index 629fa9a2c7..0000000000 --- a/svelte-slash-menu/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-slash-menu/src/app.css b/svelte-slash-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-slash-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-slash-menu/src/components/editor/examples/slash-menu/editor.svelte b/svelte-slash-menu/src/components/editor/examples/slash-menu/editor.svelte deleted file mode 100644 index ba6f313174..0000000000 --- a/svelte-slash-menu/src/components/editor/examples/slash-menu/editor.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - - -
-
-
- -
-
-
diff --git a/svelte-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/svelte-slash-menu/src/components/editor/examples/slash-menu/extension.ts deleted file mode 100644 index 0edda60136..0000000000 --- a/svelte-slash-menu/src/components/editor/examples/slash-menu/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-slash-menu/src/components/editor/examples/slash-menu/index.ts b/svelte-slash-menu/src/components/editor/examples/slash-menu/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-slash-menu/src/components/editor/examples/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-slash-menu/src/components/editor/ui/slash-menu/index.ts b/svelte-slash-menu/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 856d4e6b43..0000000000 --- a/svelte-slash-menu/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu.svelte' diff --git a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.svelte b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.svelte deleted file mode 100644 index 37cea8de67..0000000000 --- a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - - No results - diff --git a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.svelte b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.svelte deleted file mode 100644 index 52126eeb68..0000000000 --- a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.svelte +++ /dev/null @@ -1,15 +0,0 @@ - - - - {props.label}{#if props.kbd}{props.kbd}{/if} - diff --git a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu.svelte b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu.svelte deleted file mode 100644 index 5da516b44f..0000000000 --- a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu.svelte +++ /dev/null @@ -1,94 +0,0 @@ - - - - - -
- $editor.commands.setParagraph()} - /> - - $editor.commands.setHeading({ level: 1 })} - /> - - $editor.commands.setHeading({ level: 2 })} - /> - - $editor.commands.setHeading({ level: 3 })} - /> - - $editor.commands.wrapInList({ kind: 'bullet' })} - /> - - $editor.commands.wrapInList({ kind: 'ordered' })} - /> - - $editor.commands.wrapInList({ kind: 'task' })} - /> - - $editor.commands.wrapInList({ kind: 'toggle' })} - /> - - $editor.commands.setBlockquote()} - /> - - $editor.commands.insertTable({ row: 3, col: 3 })} - /> - - $editor.commands.insertHorizontalRule()} - /> - - $editor.commands.setCodeBlock()} - /> - - -
-
-
-
diff --git a/svelte-slash-menu/src/main.ts b/svelte-slash-menu/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-slash-menu/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-slash-menu/src/vite-env.d.ts b/svelte-slash-menu/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-slash-menu/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-slash-menu/svelte.config.js b/svelte-slash-menu/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-slash-menu/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-slash-menu/tsconfig.json b/svelte-slash-menu/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-slash-menu/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-slash-menu/tsconfig.node.json b/svelte-slash-menu/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-slash-menu/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-slash-menu/vite.config.ts b/svelte-slash-menu/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-slash-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-strike/.gitignore b/svelte-strike/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-strike/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-strike/README.md b/svelte-strike/README.md deleted file mode 100644 index 306ffd4c85..0000000000 --- a/svelte-strike/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-strike - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-strike) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-strike) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-strike svelte-strike -cd svelte-strike -npm install -npm run dev -``` diff --git a/svelte-strike/index.html b/svelte-strike/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-strike/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-strike/package.json b/svelte-strike/package.json deleted file mode 100644 index d32ce34c2f..0000000000 --- a/svelte-strike/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-strike", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-strike/src/App.svelte b/svelte-strike/src/App.svelte deleted file mode 100644 index 27c31707c2..0000000000 --- a/svelte-strike/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-strike/src/app.css b/svelte-strike/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-strike/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-strike/src/components/editor/examples/strike/editor.svelte b/svelte-strike/src/components/editor/examples/strike/editor.svelte deleted file mode 100644 index 98cf2aa710..0000000000 --- a/svelte-strike/src/components/editor/examples/strike/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-strike/src/components/editor/examples/strike/extension.ts b/svelte-strike/src/components/editor/examples/strike/extension.ts deleted file mode 100644 index c013303ccc..0000000000 --- a/svelte-strike/src/components/editor/examples/strike/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineStrike(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-strike/src/components/editor/examples/strike/index.ts b/svelte-strike/src/components/editor/examples/strike/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-strike/src/components/editor/examples/strike/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-strike/src/components/editor/examples/strike/toolbar.svelte b/svelte-strike/src/components/editor/examples/strike/toolbar.svelte deleted file mode 100644 index c8742e25f7..0000000000 --- a/svelte-strike/src/components/editor/examples/strike/toolbar.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - -
- -
diff --git a/svelte-strike/src/components/editor/sample/sample-doc-strike.ts b/svelte-strike/src/components/editor/sample/sample-doc-strike.ts deleted file mode 100644 index 2e025e9b02..0000000000 --- a/svelte-strike/src/components/editor/sample/sample-doc-strike.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'This is strike', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/svelte-strike/src/components/editor/ui/button/button.svelte b/svelte-strike/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-strike/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-strike/src/components/editor/ui/button/index.ts b/svelte-strike/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-strike/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-strike/src/main.ts b/svelte-strike/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-strike/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-strike/src/vite-env.d.ts b/svelte-strike/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-strike/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-strike/svelte.config.js b/svelte-strike/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-strike/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-strike/tsconfig.json b/svelte-strike/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-strike/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-strike/tsconfig.node.json b/svelte-strike/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-strike/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-strike/vite.config.ts b/svelte-strike/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-strike/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-sub-sup/.gitignore b/svelte-sub-sup/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-sub-sup/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-sub-sup/README.md b/svelte-sub-sup/README.md deleted file mode 100644 index 4259ee389e..0000000000 --- a/svelte-sub-sup/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-sub-sup - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-sub-sup) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-sub-sup) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-sub-sup svelte-sub-sup -cd svelte-sub-sup -npm install -npm run dev -``` diff --git a/svelte-sub-sup/index.html b/svelte-sub-sup/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-sub-sup/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-sub-sup/package.json b/svelte-sub-sup/package.json deleted file mode 100644 index a98803cfab..0000000000 --- a/svelte-sub-sup/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-sub-sup", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-sub-sup/src/App.svelte b/svelte-sub-sup/src/App.svelte deleted file mode 100644 index 0c05524f5f..0000000000 --- a/svelte-sub-sup/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-sub-sup/src/app.css b/svelte-sub-sup/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-sub-sup/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-sub-sup/src/components/editor/examples/sub-sup/editor.svelte b/svelte-sub-sup/src/components/editor/examples/sub-sup/editor.svelte deleted file mode 100644 index d70be85ed1..0000000000 --- a/svelte-sub-sup/src/components/editor/examples/sub-sup/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/svelte-sub-sup/src/components/editor/examples/sub-sup/extension.ts deleted file mode 100644 index bd67245f86..0000000000 --- a/svelte-sub-sup/src/components/editor/examples/sub-sup/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineMarkInputRule } from 'prosekit/extensions/input-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineSubscript } from 'prosekit/extensions/subscript' -import { defineSuperscript } from 'prosekit/extensions/superscript' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineSubscript(), - defineSuperscript(), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ - : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, - type: 'subscript', - }), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ - : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, - type: 'superscript', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-sub-sup/src/components/editor/examples/sub-sup/index.ts b/svelte-sub-sup/src/components/editor/examples/sub-sup/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-sub-sup/src/components/editor/examples/sub-sup/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-sub-sup/src/components/editor/examples/sub-sup/toolbar.svelte b/svelte-sub-sup/src/components/editor/examples/sub-sup/toolbar.svelte deleted file mode 100644 index 6ea215bc21..0000000000 --- a/svelte-sub-sup/src/components/editor/examples/sub-sup/toolbar.svelte +++ /dev/null @@ -1,42 +0,0 @@ - - -
- - -
diff --git a/svelte-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/svelte-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts deleted file mode 100644 index 011be750dc..0000000000 --- a/svelte-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'H', - }, - { - type: 'text', - marks: [ - { - type: 'subscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: 'O is water. x', - }, - { - type: 'text', - marks: [ - { - type: 'superscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: ' is a square.', - }, - ], - }, - ], -} diff --git a/svelte-sub-sup/src/components/editor/ui/button/button.svelte b/svelte-sub-sup/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-sub-sup/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-sub-sup/src/components/editor/ui/button/index.ts b/svelte-sub-sup/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-sub-sup/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-sub-sup/src/main.ts b/svelte-sub-sup/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-sub-sup/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-sub-sup/src/vite-env.d.ts b/svelte-sub-sup/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-sub-sup/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-sub-sup/svelte.config.js b/svelte-sub-sup/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-sub-sup/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-sub-sup/tsconfig.json b/svelte-sub-sup/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-sub-sup/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-sub-sup/tsconfig.node.json b/svelte-sub-sup/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-sub-sup/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-sub-sup/vite.config.ts b/svelte-sub-sup/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-sub-sup/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-table/.gitignore b/svelte-table/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-table/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-table/README.md b/svelte-table/README.md deleted file mode 100644 index 160a9975ef..0000000000 --- a/svelte-table/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-table - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-table) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-table) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-table svelte-table -cd svelte-table -npm install -npm run dev -``` diff --git a/svelte-table/index.html b/svelte-table/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-table/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-table/package.json b/svelte-table/package.json deleted file mode 100644 index c151d237af..0000000000 --- a/svelte-table/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-table", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-table/src/App.svelte b/svelte-table/src/App.svelte deleted file mode 100644 index e32b152299..0000000000 --- a/svelte-table/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-table/src/app.css b/svelte-table/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-table/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-table/src/components/editor/examples/table/editor.svelte b/svelte-table/src/components/editor/examples/table/editor.svelte deleted file mode 100644 index 26cf0c7885..0000000000 --- a/svelte-table/src/components/editor/examples/table/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
-
-
- -
-
-
diff --git a/svelte-table/src/components/editor/examples/table/extension.ts b/svelte-table/src/components/editor/examples/table/extension.ts deleted file mode 100644 index ee7b142041..0000000000 --- a/svelte-table/src/components/editor/examples/table/extension.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineTable(), - defineHistory(), - defineGapCursor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-table/src/components/editor/examples/table/index.ts b/svelte-table/src/components/editor/examples/table/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-table/src/components/editor/examples/table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-table/src/components/editor/sample/sample-doc-table.ts b/svelte-table/src/components/editor/sample/sample-doc-table.ts deleted file mode 100644 index c737121672..0000000000 --- a/svelte-table/src/components/editor/sample/sample-doc-table.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D1', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D2', - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], -} diff --git a/svelte-table/src/components/editor/ui/table-handle/index.ts b/svelte-table/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 308cef59de..0000000000 --- a/svelte-table/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle.svelte' diff --git a/svelte-table/src/components/editor/ui/table-handle/table-handle.svelte b/svelte-table/src/components/editor/ui/table-handle/table-handle.svelte deleted file mode 100644 index fc91f9a438..0000000000 --- a/svelte-table/src/components/editor/ui/table-handle/table-handle.svelte +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - -
-
- - - {#if $state.addTableColumnBefore.canExec} - - Insert Left - - {/if} - {#if $state.addTableColumnAfter.canExec} - - Insert Right - - {/if} - {#if $state.deleteCellSelection.canExec} - - Clear Contents - Del - - {/if} - {#if $state.deleteTableColumn.canExec} - - Delete Column - - {/if} - {#if $state.deleteTable.canExec} - - Delete Table - - {/if} - - -
-
-
- - - - -
-
- - - {#if $state.addTableRowAbove.canExec} - - Insert Above - - {/if} - {#if $state.addTableRowBelow.canExec} - - Insert Below - - {/if} - {#if $state.deleteCellSelection.canExec} - - Clear Contents - Del - - {/if} - {#if $state.deleteTableRow.canExec} - - Delete Row - - {/if} - {#if $state.deleteTable.canExec} - - Delete Table - - {/if} - - -
-
-
-
diff --git a/svelte-table/src/main.ts b/svelte-table/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-table/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-table/src/vite-env.d.ts b/svelte-table/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-table/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-table/svelte.config.js b/svelte-table/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-table/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-table/tsconfig.json b/svelte-table/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-table/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-table/tsconfig.node.json b/svelte-table/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-table/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-table/vite.config.ts b/svelte-table/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-table/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-text-align/.gitignore b/svelte-text-align/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-text-align/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-text-align/README.md b/svelte-text-align/README.md deleted file mode 100644 index 39cfebd9d6..0000000000 --- a/svelte-text-align/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-text-align - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-text-align) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-text-align) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-text-align svelte-text-align -cd svelte-text-align -npm install -npm run dev -``` diff --git a/svelte-text-align/index.html b/svelte-text-align/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-text-align/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-text-align/package.json b/svelte-text-align/package.json deleted file mode 100644 index f1fb1a6ce6..0000000000 --- a/svelte-text-align/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-text-align", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-text-align/src/App.svelte b/svelte-text-align/src/App.svelte deleted file mode 100644 index d521e585a0..0000000000 --- a/svelte-text-align/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-text-align/src/app.css b/svelte-text-align/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-text-align/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-text-align/src/components/editor/examples/text-align/editor.svelte b/svelte-text-align/src/components/editor/examples/text-align/editor.svelte deleted file mode 100644 index 860777b581..0000000000 --- a/svelte-text-align/src/components/editor/examples/text-align/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-text-align/src/components/editor/examples/text-align/extension.ts b/svelte-text-align/src/components/editor/examples/text-align/extension.ts deleted file mode 100644 index f1ae44dc7c..0000000000 --- a/svelte-text-align/src/components/editor/examples/text-align/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineTextAlign } from 'prosekit/extensions/text-align' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextAlign({ types: ['paragraph', 'heading'] }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-text-align/src/components/editor/examples/text-align/index.ts b/svelte-text-align/src/components/editor/examples/text-align/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-text-align/src/components/editor/examples/text-align/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-text-align/src/components/editor/examples/text-align/toolbar.svelte b/svelte-text-align/src/components/editor/examples/text-align/toolbar.svelte deleted file mode 100644 index b15ea499a9..0000000000 --- a/svelte-text-align/src/components/editor/examples/text-align/toolbar.svelte +++ /dev/null @@ -1,76 +0,0 @@ - - -
- - - - - - - -
diff --git a/svelte-text-align/src/components/editor/sample/sample-doc-text-align.ts b/svelte-text-align/src/components/editor/sample/sample-doc-text-align.ts deleted file mode 100644 index 0724cea4f7..0000000000 --- a/svelte-text-align/src/components/editor/sample/sample-doc-text-align.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Heading', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'left', - }, - content: [ - { - type: 'text', - text: 'First paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Second paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'right', - }, - content: [ - { - type: 'text', - text: 'Third paragraph', - }, - ], - }, - ], -} diff --git a/svelte-text-align/src/components/editor/ui/button/button.svelte b/svelte-text-align/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-text-align/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-text-align/src/components/editor/ui/button/index.ts b/svelte-text-align/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-text-align/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-text-align/src/main.ts b/svelte-text-align/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-text-align/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-text-align/src/vite-env.d.ts b/svelte-text-align/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-text-align/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-text-align/svelte.config.js b/svelte-text-align/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-text-align/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-text-align/tsconfig.json b/svelte-text-align/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-text-align/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-text-align/tsconfig.node.json b/svelte-text-align/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-text-align/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-text-align/vite.config.ts b/svelte-text-align/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-text-align/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-text-color/.gitignore b/svelte-text-color/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-text-color/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-text-color/README.md b/svelte-text-color/README.md deleted file mode 100644 index ca7ea8911c..0000000000 --- a/svelte-text-color/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-text-color - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-text-color) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-text-color) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-text-color svelte-text-color -cd svelte-text-color -npm install -npm run dev -``` diff --git a/svelte-text-color/index.html b/svelte-text-color/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-text-color/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-text-color/package.json b/svelte-text-color/package.json deleted file mode 100644 index 37a4671e3e..0000000000 --- a/svelte-text-color/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-text-color", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-text-color/src/App.svelte b/svelte-text-color/src/App.svelte deleted file mode 100644 index 420cbe9629..0000000000 --- a/svelte-text-color/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-text-color/src/app.css b/svelte-text-color/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-text-color/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-text-color/src/components/editor/examples/text-color/editor.svelte b/svelte-text-color/src/components/editor/examples/text-color/editor.svelte deleted file mode 100644 index dbea1ffc04..0000000000 --- a/svelte-text-color/src/components/editor/examples/text-color/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
-
-
- -
-
-
diff --git a/svelte-text-color/src/components/editor/examples/text-color/extension.ts b/svelte-text-color/src/components/editor/examples/text-color/extension.ts deleted file mode 100644 index d35d9d5c22..0000000000 --- a/svelte-text-color/src/components/editor/examples/text-color/extension.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineBackgroundColor } from 'prosekit/extensions/background-color' -import { defineTextColor } from 'prosekit/extensions/text-color' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextColor(), - defineBackgroundColor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-text-color/src/components/editor/examples/text-color/index.ts b/svelte-text-color/src/components/editor/examples/text-color/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-text-color/src/components/editor/examples/text-color/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-text-color/src/components/editor/examples/text-color/inline-menu.svelte b/svelte-text-color/src/components/editor/examples/text-color/inline-menu.svelte deleted file mode 100644 index 7e2f79c8b0..0000000000 --- a/svelte-text-color/src/components/editor/examples/text-color/inline-menu.svelte +++ /dev/null @@ -1,127 +0,0 @@ - - - open = event.detail} -> - - -
-
-
Text color
-
- {#each $textColorState as color (color.label)} - - {/each} -
-
-
-
Background color
-
- {#each $backgroundColorState as color (color.label)} - - {/each} -
-
-
-
-
-
diff --git a/svelte-text-color/src/components/editor/sample/sample-doc-text-color.ts b/svelte-text-color/src/components/editor/sample/sample-doc-text-color.ts deleted file mode 100644 index a4efe4308d..0000000000 --- a/svelte-text-color/src/components/editor/sample/sample-doc-text-color.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#ef4444', - }, - }, - ], - text: 'Select', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#f97316', - }, - }, - ], - text: 'some', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#eab308', - }, - }, - ], - text: 'text', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#22c55e', - }, - }, - ], - text: 'to', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#3b82f6', - }, - }, - ], - text: 'change', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#6366f1', - }, - }, - ], - text: 'the', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#a855f7', - }, - }, - ], - text: 'color', - }, - ], - }, - ], -} diff --git a/svelte-text-color/src/components/editor/ui/button/button.svelte b/svelte-text-color/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-text-color/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-text-color/src/components/editor/ui/button/index.ts b/svelte-text-color/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-text-color/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-text-color/src/main.ts b/svelte-text-color/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-text-color/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-text-color/src/vite-env.d.ts b/svelte-text-color/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-text-color/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-text-color/svelte.config.js b/svelte-text-color/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-text-color/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-text-color/tsconfig.json b/svelte-text-color/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-text-color/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-text-color/tsconfig.node.json b/svelte-text-color/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-text-color/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-text-color/vite.config.ts b/svelte-text-color/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-text-color/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-toolbar/.gitignore b/svelte-toolbar/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-toolbar/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-toolbar/README.md b/svelte-toolbar/README.md deleted file mode 100644 index 9213892f0c..0000000000 --- a/svelte-toolbar/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-toolbar - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-toolbar) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-toolbar) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-toolbar svelte-toolbar -cd svelte-toolbar -npm install -npm run dev -``` diff --git a/svelte-toolbar/index.html b/svelte-toolbar/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-toolbar/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-toolbar/package.json b/svelte-toolbar/package.json deleted file mode 100644 index 02166da851..0000000000 --- a/svelte-toolbar/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-toolbar", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-toolbar/src/App.svelte b/svelte-toolbar/src/App.svelte deleted file mode 100644 index fec082259a..0000000000 --- a/svelte-toolbar/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-toolbar/src/app.css b/svelte-toolbar/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-toolbar/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-toolbar/src/components/editor/examples/toolbar/editor.svelte b/svelte-toolbar/src/components/editor/examples/toolbar/editor.svelte deleted file mode 100644 index a637d4c3d3..0000000000 --- a/svelte-toolbar/src/components/editor/examples/toolbar/editor.svelte +++ /dev/null @@ -1,24 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-toolbar/src/components/editor/examples/toolbar/extension.ts b/svelte-toolbar/src/components/editor/examples/toolbar/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/svelte-toolbar/src/components/editor/examples/toolbar/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/svelte-toolbar/src/components/editor/examples/toolbar/index.ts b/svelte-toolbar/src/components/editor/examples/toolbar/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-toolbar/src/components/editor/examples/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-toolbar/src/components/editor/sample/sample-uploader.ts b/svelte-toolbar/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/svelte-toolbar/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/svelte-toolbar/src/components/editor/ui/button/button.svelte b/svelte-toolbar/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-toolbar/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-toolbar/src/components/editor/ui/button/index.ts b/svelte-toolbar/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-toolbar/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/svelte-toolbar/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-toolbar/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-toolbar/src/components/editor/ui/toolbar/index.ts b/svelte-toolbar/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-toolbar/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-toolbar/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-toolbar/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-toolbar/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-toolbar/src/main.ts b/svelte-toolbar/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-toolbar/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-toolbar/src/vite-env.d.ts b/svelte-toolbar/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-toolbar/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-toolbar/svelte.config.js b/svelte-toolbar/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-toolbar/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-toolbar/tsconfig.json b/svelte-toolbar/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-toolbar/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-toolbar/tsconfig.node.json b/svelte-toolbar/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-toolbar/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-toolbar/vite.config.ts b/svelte-toolbar/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-toolbar/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-typography/.gitignore b/svelte-typography/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-typography/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-typography/README.md b/svelte-typography/README.md deleted file mode 100644 index 569126dbd4..0000000000 --- a/svelte-typography/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-typography - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-typography) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-typography) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-typography svelte-typography -cd svelte-typography -npm install -npm run dev -``` diff --git a/svelte-typography/index.html b/svelte-typography/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-typography/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-typography/package.json b/svelte-typography/package.json deleted file mode 100644 index 88ab993977..0000000000 --- a/svelte-typography/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "example-svelte-typography", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-typography/src/App.svelte b/svelte-typography/src/App.svelte deleted file mode 100644 index 2a693edc72..0000000000 --- a/svelte-typography/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-typography/src/app.css b/svelte-typography/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-typography/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-typography/src/components/editor/examples/typography/editor.svelte b/svelte-typography/src/components/editor/examples/typography/editor.svelte deleted file mode 100644 index 9bf6b8432f..0000000000 --- a/svelte-typography/src/components/editor/examples/typography/editor.svelte +++ /dev/null @@ -1,32 +0,0 @@ - - - -
-
-
- - -
-
-
diff --git a/svelte-typography/src/components/editor/examples/typography/extension.ts b/svelte-typography/src/components/editor/examples/typography/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/svelte-typography/src/components/editor/examples/typography/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-typography/src/components/editor/examples/typography/index.ts b/svelte-typography/src/components/editor/examples/typography/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-typography/src/components/editor/examples/typography/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-typography/src/components/editor/sample/katex.ts b/svelte-typography/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/svelte-typography/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/svelte-typography/src/components/editor/sample/sample-doc-typography.ts b/svelte-typography/src/components/editor/sample/sample-doc-typography.ts deleted file mode 100644 index db18b8155c..0000000000 --- a/svelte-typography/src/components/editor/sample/sample-doc-typography.ts +++ /dev/null @@ -1,693 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'ProseKit Typography', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This example shows the typography styles provided by ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'prosekit/basic/typography.css', - }, - { - type: 'text', - text: '.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Inline marks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Text can be formatted in different ways: ', - }, - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'bold text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'italic text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'underlined text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'strikethrough text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'inline code', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://example.com', - target: null, - rel: null, - }, - }, - ], - text: 'links', - }, - { - type: 'text', - text: ',', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'and hard breaks (Shift+Enter).', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Headings', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Heading 1', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Heading 2', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Heading 3', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 4, - }, - content: [ - { - type: 'text', - text: 'Heading 4', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 5, - }, - content: [ - { - type: 'text', - text: 'Heading 5', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 6, - }, - content: [ - { - type: 'text', - text: 'Heading 6', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Lists', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here are different types of lists:', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 1', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 2', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item A', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item B', - }, - ], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'First ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Second ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: true, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Completed task', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Pending task', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Blockquotes', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: '', - }, - content: [ - { - type: 'text', - text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Horizontal Rule', - }, - ], - }, - { - type: 'horizontalRule', - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blurred/640x360/42', - }, - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Tables', - }, - ], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 1', - }, - ], - }, - ], - }, - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 3', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 4', - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Math', - }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Inline math like Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text.' }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Block-level equations are displayed on their own line:', - }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - ], -} diff --git a/svelte-typography/src/components/editor/ui/block-handle/block-handle.svelte b/svelte-typography/src/components/editor/ui/block-handle/block-handle.svelte deleted file mode 100644 index f67e42dc91..0000000000 --- a/svelte-typography/src/components/editor/ui/block-handle/block-handle.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - -
-
- -
-
-
-
-
diff --git a/svelte-typography/src/components/editor/ui/block-handle/index.ts b/svelte-typography/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 6d21191384..0000000000 --- a/svelte-typography/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.svelte' diff --git a/svelte-typography/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/svelte-typography/src/components/editor/ui/drop-indicator/drop-indicator.svelte deleted file mode 100644 index 7f6cac1db0..0000000000 --- a/svelte-typography/src/components/editor/ui/drop-indicator/drop-indicator.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-typography/src/components/editor/ui/drop-indicator/index.ts b/svelte-typography/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index 06e89357ed..0000000000 --- a/svelte-typography/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator.svelte' diff --git a/svelte-typography/src/main.ts b/svelte-typography/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-typography/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-typography/src/vite-env.d.ts b/svelte-typography/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-typography/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-typography/svelte.config.js b/svelte-typography/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-typography/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-typography/tsconfig.json b/svelte-typography/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-typography/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-typography/tsconfig.node.json b/svelte-typography/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-typography/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-typography/vite.config.ts b/svelte-typography/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-typography/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-underline/.gitignore b/svelte-underline/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-underline/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-underline/README.md b/svelte-underline/README.md deleted file mode 100644 index 3e08a9ca7a..0000000000 --- a/svelte-underline/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-underline - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-underline) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-underline) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-underline svelte-underline -cd svelte-underline -npm install -npm run dev -``` diff --git a/svelte-underline/index.html b/svelte-underline/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-underline/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-underline/package.json b/svelte-underline/package.json deleted file mode 100644 index f4a2992e0c..0000000000 --- a/svelte-underline/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-underline", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-underline/src/App.svelte b/svelte-underline/src/App.svelte deleted file mode 100644 index 93deae80ee..0000000000 --- a/svelte-underline/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-underline/src/app.css b/svelte-underline/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-underline/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-underline/src/components/editor/examples/underline/editor.svelte b/svelte-underline/src/components/editor/examples/underline/editor.svelte deleted file mode 100644 index b005c3ee6b..0000000000 --- a/svelte-underline/src/components/editor/examples/underline/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-underline/src/components/editor/examples/underline/extension.ts b/svelte-underline/src/components/editor/examples/underline/extension.ts deleted file mode 100644 index 16a9b58284..0000000000 --- a/svelte-underline/src/components/editor/examples/underline/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineUnderline(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-underline/src/components/editor/examples/underline/index.ts b/svelte-underline/src/components/editor/examples/underline/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-underline/src/components/editor/examples/underline/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-underline/src/components/editor/sample/sample-doc-underline.ts b/svelte-underline/src/components/editor/sample/sample-doc-underline.ts deleted file mode 100644 index 6af561064b..0000000000 --- a/svelte-underline/src/components/editor/sample/sample-doc-underline.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'This is underline', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/svelte-underline/src/components/editor/ui/button/button.svelte b/svelte-underline/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-underline/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-underline/src/components/editor/ui/button/index.ts b/svelte-underline/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-underline/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-underline/src/components/editor/ui/image-upload-popover/index.ts b/svelte-underline/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-underline/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-underline/src/components/editor/ui/toolbar/index.ts b/svelte-underline/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-underline/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-underline/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-underline/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-underline/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-underline/src/main.ts b/svelte-underline/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-underline/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-underline/src/vite-env.d.ts b/svelte-underline/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-underline/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-underline/svelte.config.js b/svelte-underline/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-underline/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-underline/tsconfig.json b/svelte-underline/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-underline/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-underline/tsconfig.node.json b/svelte-underline/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-underline/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-underline/vite.config.ts b/svelte-underline/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-underline/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-unmount/.gitignore b/svelte-unmount/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-unmount/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-unmount/README.md b/svelte-unmount/README.md deleted file mode 100644 index d0809e179b..0000000000 --- a/svelte-unmount/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-unmount - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-unmount) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-unmount) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-unmount svelte-unmount -cd svelte-unmount -npm install -npm run dev -``` diff --git a/svelte-unmount/index.html b/svelte-unmount/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-unmount/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-unmount/package.json b/svelte-unmount/package.json deleted file mode 100644 index d69b69c2df..0000000000 --- a/svelte-unmount/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-unmount", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-unmount/src/App.svelte b/svelte-unmount/src/App.svelte deleted file mode 100644 index 8fb35fbcfe..0000000000 --- a/svelte-unmount/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-unmount/src/app.css b/svelte-unmount/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-unmount/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-unmount/src/components/editor/examples/unmount/editor-component.svelte b/svelte-unmount/src/components/editor/examples/unmount/editor-component.svelte deleted file mode 100644 index 1096263f08..0000000000 --- a/svelte-unmount/src/components/editor/examples/unmount/editor-component.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - -
-
-
- -
-
- -
diff --git a/svelte-unmount/src/components/editor/examples/unmount/editor.svelte b/svelte-unmount/src/components/editor/examples/unmount/editor.svelte deleted file mode 100644 index 17ed0a26fa..0000000000 --- a/svelte-unmount/src/components/editor/examples/unmount/editor.svelte +++ /dev/null @@ -1,37 +0,0 @@ - - -
-
- - {#each editorKeys as key (key)} - - {/each} -
- {#each editorKeys as key (key)} -
- -
- {/each} -
diff --git a/svelte-unmount/src/components/editor/examples/unmount/extension-component.svelte b/svelte-unmount/src/components/editor/examples/unmount/extension-component.svelte deleted file mode 100644 index eaf6f0d953..0000000000 --- a/svelte-unmount/src/components/editor/examples/unmount/extension-component.svelte +++ /dev/null @@ -1,13 +0,0 @@ - diff --git a/svelte-unmount/src/components/editor/examples/unmount/index.ts b/svelte-unmount/src/components/editor/examples/unmount/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-unmount/src/components/editor/examples/unmount/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-unmount/src/components/editor/ui/button/button.svelte b/svelte-unmount/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-unmount/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-unmount/src/components/editor/ui/button/index.ts b/svelte-unmount/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-unmount/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-unmount/src/components/editor/ui/inline-menu/index.ts b/svelte-unmount/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index bf78dd2139..0000000000 --- a/svelte-unmount/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-unmount/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-unmount/src/components/editor/ui/inline-menu/inline-menu.svelte deleted file mode 100644 index 989f0c013b..0000000000 --- a/svelte-unmount/src/components/editor/ui/inline-menu/inline-menu.svelte +++ /dev/null @@ -1,207 +0,0 @@ - - - { - if (!event.detail) linkMenuOpen = false - }} -> - - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.link?.canExec && $items.link} - - {/if} - - - - - { - linkMenuOpen = event.detail - }} -> - - - {#if linkMenuOpen && $items.link} -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- {/if} - {#if $items.link?.isActive} - - {/if} -
-
-
diff --git a/svelte-unmount/src/main.ts b/svelte-unmount/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-unmount/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-unmount/src/vite-env.d.ts b/svelte-unmount/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-unmount/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-unmount/svelte.config.js b/svelte-unmount/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-unmount/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-unmount/tsconfig.json b/svelte-unmount/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-unmount/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-unmount/tsconfig.node.json b/svelte-unmount/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-unmount/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-unmount/vite.config.ts b/svelte-unmount/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-unmount/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-user-menu-dynamic/.gitignore b/svelte-user-menu-dynamic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-user-menu-dynamic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-user-menu-dynamic/README.md b/svelte-user-menu-dynamic/README.md deleted file mode 100644 index 6d55f1a102..0000000000 --- a/svelte-user-menu-dynamic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-user-menu-dynamic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-user-menu-dynamic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-user-menu-dynamic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-user-menu-dynamic svelte-user-menu-dynamic -cd svelte-user-menu-dynamic -npm install -npm run dev -``` diff --git a/svelte-user-menu-dynamic/index.html b/svelte-user-menu-dynamic/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-user-menu-dynamic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-user-menu-dynamic/package.json b/svelte-user-menu-dynamic/package.json deleted file mode 100644 index 1507ecc442..0000000000 --- a/svelte-user-menu-dynamic/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-user-menu-dynamic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-user-menu-dynamic/src/App.svelte b/svelte-user-menu-dynamic/src/App.svelte deleted file mode 100644 index a0c9a2f997..0000000000 --- a/svelte-user-menu-dynamic/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-user-menu-dynamic/src/app.css b/svelte-user-menu-dynamic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-user-menu-dynamic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.svelte b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.svelte deleted file mode 100644 index 0d6b8a0ec0..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - - -
-
-
- -
-
-
diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts deleted file mode 100644 index ff2c40b104..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.svelte.ts b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.svelte.ts deleted file mode 100644 index 1fba95e9e0..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.svelte.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { queryUsers, type User } from '../../sample/sample-query-users' - -export function useUserQuery( - getQuery: () => string, - getEnabled: () => boolean, -) { - let loading = $state(true) - let users = $state([]) - - $effect(() => { - const query = getQuery() - const enabled = getEnabled() - - if (!enabled) { - users = [] - return - } - - loading = true - let cancelled = false - void queryUsers(query).then((result) => { - if (cancelled) { - return - } - users = result - loading = false - }) - return () => { - cancelled = true - } - }) - - return { - getLoading: () => loading, - getUsers: () => users, - } -} diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.svelte b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.svelte deleted file mode 100644 index 831ea21723..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.svelte +++ /dev/null @@ -1,25 +0,0 @@ - - - diff --git a/svelte-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/svelte-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts deleted file mode 100644 index ab78fd5525..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { users } from './sample-user-data' - -export interface User { - id: number - name: string -} - -const connectHandlers: VoidFunction[] = [] -let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' - -/** - * A utility function to simulate different network states. Useful for testing. - * - * @internal - */ -export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { - networkStatus = status - if (status !== 'offline') { - connectHandlers.forEach((handler) => handler()) - connectHandlers.length = 0 - } -} - -/** - * Simulate a user searching with some delay. - */ -export async function queryUsers(query: string): Promise { - if (networkStatus === 'offline') { - await new Promise((resolve) => connectHandlers.push(resolve)) - } - if (networkStatus === 'slow') { - await new Promise((resolve) => setTimeout(resolve, 300)) - } - - const normalizedQuery = query.toLowerCase().trim() - const filteredUsers = users - .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) - .slice(0, 10) - return filteredUsers -} diff --git a/svelte-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/svelte-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index 7dbbd80d0e..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu.svelte' diff --git a/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.svelte b/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.svelte deleted file mode 100644 index 5c0475d87e..0000000000 --- a/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.svelte +++ /dev/null @@ -1,70 +0,0 @@ - - - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} -> - - -
- - {loading ? 'Loading...' : 'No results'} - - - {#each props.users as user (user.id)} - handleUserInsert(user.id, user.name)} - > - {#if loading} - - {user.name} - - {:else} - - {user.name} - - {/if} - - {/each} -
-
-
-
diff --git a/svelte-user-menu-dynamic/src/main.ts b/svelte-user-menu-dynamic/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-user-menu-dynamic/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-user-menu-dynamic/src/vite-env.d.ts b/svelte-user-menu-dynamic/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-user-menu-dynamic/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-user-menu-dynamic/svelte.config.js b/svelte-user-menu-dynamic/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-user-menu-dynamic/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-user-menu-dynamic/tsconfig.json b/svelte-user-menu-dynamic/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-user-menu-dynamic/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-user-menu-dynamic/tsconfig.node.json b/svelte-user-menu-dynamic/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-user-menu-dynamic/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-user-menu-dynamic/vite.config.ts b/svelte-user-menu-dynamic/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-user-menu-dynamic/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-user-menu/.gitignore b/svelte-user-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-user-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-user-menu/README.md b/svelte-user-menu/README.md deleted file mode 100644 index 91b1d7f782..0000000000 --- a/svelte-user-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-user-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-user-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-user-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-user-menu svelte-user-menu -cd svelte-user-menu -npm install -npm run dev -``` diff --git a/svelte-user-menu/index.html b/svelte-user-menu/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-user-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-user-menu/package.json b/svelte-user-menu/package.json deleted file mode 100644 index 2c205f468a..0000000000 --- a/svelte-user-menu/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-user-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-user-menu/src/App.svelte b/svelte-user-menu/src/App.svelte deleted file mode 100644 index 4ff7b9d541..0000000000 --- a/svelte-user-menu/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-user-menu/src/app.css b/svelte-user-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-user-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-user-menu/src/components/editor/examples/user-menu/editor.svelte b/svelte-user-menu/src/components/editor/examples/user-menu/editor.svelte deleted file mode 100644 index 701352a92e..0000000000 --- a/svelte-user-menu/src/components/editor/examples/user-menu/editor.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - - -
-
-
- - -
-
-
diff --git a/svelte-user-menu/src/components/editor/examples/user-menu/extension.ts b/svelte-user-menu/src/components/editor/examples/user-menu/extension.ts deleted file mode 100644 index 56a97a4779..0000000000 --- a/svelte-user-menu/src/components/editor/examples/user-menu/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone or # to tag something...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-user-menu/src/components/editor/examples/user-menu/index.ts b/svelte-user-menu/src/components/editor/examples/user-menu/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-user-menu/src/components/editor/examples/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-user-menu/src/components/editor/sample/sample-tag-data.ts b/svelte-user-menu/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/svelte-user-menu/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/svelte-user-menu/src/components/editor/sample/sample-user-data.ts b/svelte-user-menu/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/svelte-user-menu/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/svelte-user-menu/src/components/editor/ui/tag-menu/index.ts b/svelte-user-menu/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index 0884d7f5a1..0000000000 --- a/svelte-user-menu/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu.svelte' diff --git a/svelte-user-menu/src/components/editor/ui/tag-menu/tag-menu.svelte b/svelte-user-menu/src/components/editor/ui/tag-menu/tag-menu.svelte deleted file mode 100644 index 8b9bf23f30..0000000000 --- a/svelte-user-menu/src/components/editor/ui/tag-menu/tag-menu.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
- - No results - - - {#each props.tags as tag (tag.id)} - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - {/each} -
-
-
-
diff --git a/svelte-user-menu/src/components/editor/ui/user-menu/index.ts b/svelte-user-menu/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index 7dbbd80d0e..0000000000 --- a/svelte-user-menu/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu.svelte' diff --git a/svelte-user-menu/src/components/editor/ui/user-menu/user-menu.svelte b/svelte-user-menu/src/components/editor/ui/user-menu/user-menu.svelte deleted file mode 100644 index 5c0475d87e..0000000000 --- a/svelte-user-menu/src/components/editor/ui/user-menu/user-menu.svelte +++ /dev/null @@ -1,70 +0,0 @@ - - - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} -> - - -
- - {loading ? 'Loading...' : 'No results'} - - - {#each props.users as user (user.id)} - handleUserInsert(user.id, user.name)} - > - {#if loading} - - {user.name} - - {:else} - - {user.name} - - {/if} - - {/each} -
-
-
-
diff --git a/svelte-user-menu/src/main.ts b/svelte-user-menu/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-user-menu/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-user-menu/src/vite-env.d.ts b/svelte-user-menu/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-user-menu/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-user-menu/svelte.config.js b/svelte-user-menu/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-user-menu/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-user-menu/tsconfig.json b/svelte-user-menu/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-user-menu/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-user-menu/tsconfig.node.json b/svelte-user-menu/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-user-menu/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-user-menu/vite.config.ts b/svelte-user-menu/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-user-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-word-counter/.gitignore b/svelte-word-counter/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-word-counter/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-word-counter/README.md b/svelte-word-counter/README.md deleted file mode 100644 index ee700b30fa..0000000000 --- a/svelte-word-counter/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-word-counter - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-word-counter) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-word-counter) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-word-counter svelte-word-counter -cd svelte-word-counter -npm install -npm run dev -``` diff --git a/svelte-word-counter/index.html b/svelte-word-counter/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-word-counter/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-word-counter/package.json b/svelte-word-counter/package.json deleted file mode 100644 index 2c1132e698..0000000000 --- a/svelte-word-counter/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-svelte-word-counter", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-word-counter/src/App.svelte b/svelte-word-counter/src/App.svelte deleted file mode 100644 index 592f106186..0000000000 --- a/svelte-word-counter/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-word-counter/src/app.css b/svelte-word-counter/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-word-counter/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-word-counter/src/components/editor/examples/word-counter/editor.svelte b/svelte-word-counter/src/components/editor/examples/word-counter/editor.svelte deleted file mode 100644 index dd19aee366..0000000000 --- a/svelte-word-counter/src/components/editor/examples/word-counter/editor.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - -
-
-
- -
-
-
diff --git a/svelte-word-counter/src/components/editor/examples/word-counter/extension.ts b/svelte-word-counter/src/components/editor/examples/word-counter/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/svelte-word-counter/src/components/editor/examples/word-counter/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/svelte-word-counter/src/components/editor/examples/word-counter/index.ts b/svelte-word-counter/src/components/editor/examples/word-counter/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-word-counter/src/components/editor/examples/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/svelte-word-counter/src/components/editor/sample/sample-doc-word-counter.ts deleted file mode 100644 index 0b5d435038..0000000000 --- a/svelte-word-counter/src/components/editor/sample/sample-doc-word-counter.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Start typing and observe the word count update below.', - }, - ], - }, - ], -} diff --git a/svelte-word-counter/src/components/editor/ui/word-counter/index.ts b/svelte-word-counter/src/components/editor/ui/word-counter/index.ts deleted file mode 100644 index e0c531aedf..0000000000 --- a/svelte-word-counter/src/components/editor/ui/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as WordCounter } from './word-counter.svelte' diff --git a/svelte-word-counter/src/components/editor/ui/word-counter/word-counter.svelte b/svelte-word-counter/src/components/editor/ui/word-counter/word-counter.svelte deleted file mode 100644 index 72c4cc2cc5..0000000000 --- a/svelte-word-counter/src/components/editor/ui/word-counter/word-counter.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - -
- Word Count: {$counts.wordCount} -
- Character Count: {$counts.characterCount} -
diff --git a/svelte-word-counter/src/main.ts b/svelte-word-counter/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-word-counter/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-word-counter/src/vite-env.d.ts b/svelte-word-counter/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-word-counter/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-word-counter/svelte.config.js b/svelte-word-counter/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-word-counter/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-word-counter/tsconfig.json b/svelte-word-counter/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-word-counter/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-word-counter/tsconfig.node.json b/svelte-word-counter/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-word-counter/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-word-counter/vite.config.ts b/svelte-word-counter/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-word-counter/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/svelte-yjs/.gitignore b/svelte-yjs/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/svelte-yjs/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/svelte-yjs/README.md b/svelte-yjs/README.md deleted file mode 100644 index 44823f7136..0000000000 --- a/svelte-yjs/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# svelte-yjs - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-yjs) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-yjs) - -Run the example locally with: - -```bash -npx degit prosekit/examples/svelte-yjs svelte-yjs -cd svelte-yjs -npm install -npm run dev -``` diff --git a/svelte-yjs/index.html b/svelte-yjs/index.html deleted file mode 100644 index 58212c2501..0000000000 --- a/svelte-yjs/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Svelte - - -
- - - diff --git a/svelte-yjs/package.json b/svelte-yjs/package.json deleted file mode 100644 index d642ab7ebc..0000000000 --- a/svelte-yjs/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "example-svelte-yjs", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-check --tsconfig ./tsconfig.json && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "y-prosemirror": "^1.3.7", - "y-protocols": "^1.0.7", - "y-websocket": "^3.0.0", - "yjs": "^13.6.30" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "@tsconfig/svelte": "^5.0.8", - "postcss": "^8.5.14", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "tslib": "^2.8.1", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/svelte-yjs/src/App.svelte b/svelte-yjs/src/App.svelte deleted file mode 100644 index 4a469f04e6..0000000000 --- a/svelte-yjs/src/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/svelte-yjs/src/app.css b/svelte-yjs/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/svelte-yjs/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/svelte-yjs/src/components/editor/examples/yjs/editor-component.svelte b/svelte-yjs/src/components/editor/examples/yjs/editor-component.svelte deleted file mode 100644 index 3ac3d77918..0000000000 --- a/svelte-yjs/src/components/editor/examples/yjs/editor-component.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - -
- -
-
-
-
-
diff --git a/svelte-yjs/src/components/editor/examples/yjs/editor.svelte b/svelte-yjs/src/components/editor/examples/yjs/editor.svelte deleted file mode 100644 index 7faf8286e1..0000000000 --- a/svelte-yjs/src/components/editor/examples/yjs/editor.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - -
- - -
diff --git a/svelte-yjs/src/components/editor/examples/yjs/extension.ts b/svelte-yjs/src/components/editor/examples/yjs/extension.ts deleted file mode 100644 index b2546b126e..0000000000 --- a/svelte-yjs/src/components/editor/examples/yjs/extension.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' -import { defineYjs } from 'prosekit/extensions/yjs' -import type { Awareness } from 'prosekit/extensions/yjs' -import type * as Y from 'yjs' - -export function defineExtension(doc: Y.Doc, awareness: Awareness) { - return union( - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineYjs({ doc, awareness }), - ) -} - -export type EditorExtension = ReturnType diff --git a/svelte-yjs/src/components/editor/examples/yjs/index.ts b/svelte-yjs/src/components/editor/examples/yjs/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/svelte-yjs/src/components/editor/examples/yjs/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-yjs/src/components/editor/ui/button/button.svelte b/svelte-yjs/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/svelte-yjs/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/svelte-yjs/src/components/editor/ui/button/index.ts b/svelte-yjs/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/svelte-yjs/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/svelte-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte deleted file mode 100644 index c80af45721..0000000000 --- a/svelte-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte +++ /dev/null @@ -1,121 +0,0 @@ - - - - - - - - - {#if !file} - - - {/if} - - {#if !url} - - - {/if} - - {#if url} - - {/if} - - {#if file} - - {/if} - - diff --git a/svelte-yjs/src/components/editor/ui/image-upload-popover/index.ts b/svelte-yjs/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index e53e71c348..0000000000 --- a/svelte-yjs/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-yjs/src/components/editor/ui/toolbar/index.ts b/svelte-yjs/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/svelte-yjs/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-yjs/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-yjs/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/svelte-yjs/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/svelte-yjs/src/main.ts b/svelte-yjs/src/main.ts deleted file mode 100644 index b4bc565380..0000000000 --- a/svelte-yjs/src/main.ts +++ /dev/null @@ -1,8 +0,0 @@ -import './app.css' - -import { mount } from 'svelte' -import App from './App.svelte' - -const app = mount(App, { target: document.getElementById('app')! }) - -export default app diff --git a/svelte-yjs/src/vite-env.d.ts b/svelte-yjs/src/vite-env.d.ts deleted file mode 100644 index 4078e7476a..0000000000 --- a/svelte-yjs/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/svelte-yjs/svelte.config.js b/svelte-yjs/svelte.config.js deleted file mode 100644 index b0683fd24d..0000000000 --- a/svelte-yjs/svelte.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' - -export default { - // Consult https://svelte.dev/docs#compile-time-svelte-preprocess - // for more information about preprocessors - preprocess: vitePreprocess(), -} diff --git a/svelte-yjs/tsconfig.json b/svelte-yjs/tsconfig.json deleted file mode 100644 index 86876593dd..0000000000 --- a/svelte-yjs/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "extends": "@tsconfig/svelte/tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "useDefineForClassFields": true, - "module": "ESNext", - "resolveJsonModule": true, - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable checkJs if you'd like to use dynamic types in JS. - * Note that setting allowJs false does not prevent the use - * of JS in `.svelte` files. - */ - "allowJs": true, - "checkJs": true, - "allowImportingTsExtensions": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/svelte-yjs/tsconfig.node.json b/svelte-yjs/tsconfig.node.json deleted file mode 100644 index 494bfe0835..0000000000 --- a/svelte-yjs/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler" - }, - "include": ["vite.config.ts"] -} diff --git a/svelte-yjs/vite.config.ts b/svelte-yjs/vite.config.ts deleted file mode 100644 index 11edea7f23..0000000000 --- a/svelte-yjs/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte(), tailwindcss()], -}) diff --git a/sveltekit-full/.gitignore b/sveltekit-full/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/sveltekit-full/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/sveltekit-full/README.md b/sveltekit-full/README.md deleted file mode 100644 index d335fd4f33..0000000000 --- a/sveltekit-full/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# sveltekit-full - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/sveltekit-full) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/sveltekit-full) - -Run the example locally with: - -```bash -npx degit prosekit/examples/sveltekit-full sveltekit-full -cd sveltekit-full -npm install -npm run dev -``` diff --git a/sveltekit-full/package.json b/sveltekit-full/package.json deleted file mode 100644 index e1d513d59f..0000000000 --- a/sveltekit-full/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "example-sveltekit-full", - "version": "0.0.1", - "private": true, - "type": "module", - "scripts": { - "build": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && vite build", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "dev": "vite dev", - "prepare": "svelte-kit sync || echo ''", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@sveltejs/adapter-auto": "^7.0.1", - "@sveltejs/kit": "^2.60.1", - "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tailwindcss/vite": "^4.3.0", - "svelte": "^5.55.7", - "svelte-check": "^4.4.8", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13" - } -} diff --git a/sveltekit-full/src/app.css b/sveltekit-full/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/sveltekit-full/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/sveltekit-full/src/app.d.ts b/sveltekit-full/src/app.d.ts deleted file mode 100644 index 367926a580..0000000000 --- a/sveltekit-full/src/app.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -// See https://kit.svelte.dev/docs/types#app -// for information about these interfaces -declare global { - namespace App { - // interface Error {} - // interface Locals {} - // interface PageData {} - // interface PageState {} - // interface Platform {} - } -} - -export {} diff --git a/sveltekit-full/src/app.html b/sveltekit-full/src/app.html deleted file mode 100644 index 84ffad1665..0000000000 --- a/sveltekit-full/src/app.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/sveltekit-full/src/components/editor/examples/full/editor.svelte b/sveltekit-full/src/components/editor/examples/full/editor.svelte deleted file mode 100644 index 09f3d7d9d3..0000000000 --- a/sveltekit-full/src/components/editor/examples/full/editor.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - - -
- -
-
- - - - - - - -
-
-
diff --git a/sveltekit-full/src/components/editor/examples/full/extension.ts b/sveltekit-full/src/components/editor/examples/full/extension.ts deleted file mode 100644 index 5fc2f60685..0000000000 --- a/sveltekit-full/src/components/editor/examples/full/extension.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineImageUploadHandler } from 'prosekit/extensions/image' -import { defineMath } from 'prosekit/extensions/math' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' -import { sampleUploader } from '../../sample/sample-uploader' -import { defineCodeBlockView } from '../../ui/code-block-view' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - defineMention(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - defineCodeBlockShiki(), - defineHorizontalRule(), - defineCodeBlockView(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/sveltekit-full/src/components/editor/examples/full/index.ts b/sveltekit-full/src/components/editor/examples/full/index.ts deleted file mode 100644 index 1933e61970..0000000000 --- a/sveltekit-full/src/components/editor/examples/full/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.svelte' diff --git a/sveltekit-full/src/components/editor/sample/katex.ts b/sveltekit-full/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/sveltekit-full/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/sveltekit-full/src/components/editor/sample/sample-doc-full.ts b/sveltekit-full/src/components/editor/sample/sample-doc-full.ts deleted file mode 100644 index 13e49b634d..0000000000 --- a/sveltekit-full/src/components/editor/sample/sample-doc-full.ts +++ /dev/null @@ -1,442 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'The editor that thinks like you' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', - }, - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'writing without barriers', - }, - { type: 'text', text: '.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Text that shines.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Make your words ' }, - { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, - { type: 'text', text: ', or ' }, - { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, - { type: 'text', text: '. Add ' }, - { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, - { type: 'text', text: ' that stands out. Create ' }, - { - type: 'text', - marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], - text: 'links', - }, - { type: 'text', text: ' that connect.' }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Select any text to format it. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '@' }, - { type: 'text', text: ' to mention ' }, - { - type: 'mention', - attrs: { id: '39', value: '@someone', kind: 'user' }, - }, - { type: 'text', text: ' or ' }, - { type: 'text', marks: [{ type: 'code' }], text: '#' }, - { type: 'text', text: ' for ' }, - { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, - { type: 'text', text: '. Press ' }, - { type: 'text', marks: [{ type: 'code' }], text: '/' }, - { type: 'text', text: " and discover what's possible." }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Lists that organize.' }], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Bullet points that guide thoughts' }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Nested lists for complex ideas' }], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sub-points flow naturally' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Tasks that focus' }], - }, - { - type: 'list', - attrs: { kind: 'task', order: null, checked: true, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Done feels good' }], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Todo drives action' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Numbered steps' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sequential thinking' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Clear progress' }], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Code that inspires.' }], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Images that captivate.' }], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/season/320x240/107', - }, - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the handle in the bottom right corner to resize.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Tables that structure.' }], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'Feature', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'How to use', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Format text' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Select and choose' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Perfect styling' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Add mentions' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Type @ and name' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Connected ideas' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Insert anything' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Press / for menu' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Endless possibilities' }], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Math that renders.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Inline math like ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' appears within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Quotes that inspire.' }], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: '"This is not just an editor. This is how writing should feel."', - }, - ], - }, - ], - }, - { type: 'horizontalRule' }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Start typing. Everything else just flows.' }, - ], - }, - ], -} diff --git a/sveltekit-full/src/components/editor/sample/sample-tag-data.ts b/sveltekit-full/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/sveltekit-full/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/sveltekit-full/src/components/editor/sample/sample-uploader.ts b/sveltekit-full/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/sveltekit-full/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/sveltekit-full/src/components/editor/sample/sample-user-data.ts b/sveltekit-full/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/sveltekit-full/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/sveltekit-full/src/components/editor/ui/block-handle/block-handle.svelte b/sveltekit-full/src/components/editor/ui/block-handle/block-handle.svelte deleted file mode 100644 index f67e42dc91..0000000000 --- a/sveltekit-full/src/components/editor/ui/block-handle/block-handle.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - -
-
- -
-
-
-
-
diff --git a/sveltekit-full/src/components/editor/ui/block-handle/index.ts b/sveltekit-full/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 6d21191384..0000000000 --- a/sveltekit-full/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.svelte' diff --git a/sveltekit-full/src/components/editor/ui/button/button.svelte b/sveltekit-full/src/components/editor/ui/button/button.svelte deleted file mode 100644 index 43680d3bf0..0000000000 --- a/sveltekit-full/src/components/editor/ui/button/button.svelte +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - {#if props.tooltip} - - - {props.tooltip} - - - {/if} - diff --git a/sveltekit-full/src/components/editor/ui/button/index.ts b/sveltekit-full/src/components/editor/ui/button/index.ts deleted file mode 100644 index 1d087605a7..0000000000 --- a/sveltekit-full/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.svelte' diff --git a/sveltekit-full/src/components/editor/ui/code-block-view/code-block-view.svelte b/sveltekit-full/src/components/editor/ui/code-block-view/code-block-view.svelte deleted file mode 100644 index aaa4617fc1..0000000000 --- a/sveltekit-full/src/components/editor/ui/code-block-view/code-block-view.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - -

diff --git a/sveltekit-full/src/components/editor/ui/code-block-view/index.ts b/sveltekit-full/src/components/editor/ui/code-block-view/index.ts
deleted file mode 100644
index eb54b2f6d9..0000000000
--- a/sveltekit-full/src/components/editor/ui/code-block-view/index.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Extension } from 'prosekit/core'
-import {
-  defineSvelteNodeView,
-  type SvelteNodeViewComponent,
-} from 'prosekit/svelte'
-
-import CodeBlockView from './code-block-view.svelte'
-
-export function defineCodeBlockView(): Extension {
-  return defineSvelteNodeView({
-    name: 'codeBlock',
-    contentAs: 'code',
-    component: CodeBlockView as SvelteNodeViewComponent,
-  })
-}
diff --git a/sveltekit-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/sveltekit-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte
deleted file mode 100644
index 7f6cac1db0..0000000000
--- a/sveltekit-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/sveltekit-full/src/components/editor/ui/drop-indicator/index.ts b/sveltekit-full/src/components/editor/ui/drop-indicator/index.ts
deleted file mode 100644
index 06e89357ed..0000000000
--- a/sveltekit-full/src/components/editor/ui/drop-indicator/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as DropIndicator } from './drop-indicator.svelte'
diff --git a/sveltekit-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/sveltekit-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
deleted file mode 100644
index c80af45721..0000000000
--- a/sveltekit-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-  
-    
-  
-
-  
-      {#if !file}
-        
-        
-      {/if}
-
-      {#if !url}
-        
-        
-      {/if}
-
-      {#if url}
-        
-      {/if}
-
-      {#if file}
-        
-      {/if}
-    
-
diff --git a/sveltekit-full/src/components/editor/ui/image-upload-popover/index.ts b/sveltekit-full/src/components/editor/ui/image-upload-popover/index.ts
deleted file mode 100644
index e53e71c348..0000000000
--- a/sveltekit-full/src/components/editor/ui/image-upload-popover/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as ImageUploadPopover } from './image-upload-popover.svelte'
diff --git a/sveltekit-full/src/components/editor/ui/image-view/image-view.svelte b/sveltekit-full/src/components/editor/ui/image-view/image-view.svelte
deleted file mode 100644
index b8f0fd3971..0000000000
--- a/sveltekit-full/src/components/editor/ui/image-view/image-view.svelte
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
- props.setAttrs(event.detail)}
->
-  {#if url && !error}
-    upload preview
-  {/if}
-  {#if uploading && !error}
-    
-
-
{Math.round(progress * 100)}%
-
- {/if} - {#if error} -
-
- -
- {/if} - -
-
-
diff --git a/sveltekit-full/src/components/editor/ui/image-view/index.ts b/sveltekit-full/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index d39bdb81e8..0000000000 --- a/sveltekit-full/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { - defineSvelteNodeView, - type SvelteNodeViewComponent, -} from 'prosekit/svelte' - -import ImageView from './image-view.svelte' - -export function defineImageView(): Extension { - return defineSvelteNodeView({ - name: 'image', - component: ImageView as SvelteNodeViewComponent, - }) -} diff --git a/sveltekit-full/src/components/editor/ui/inline-menu/index.ts b/sveltekit-full/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index bf78dd2139..0000000000 --- a/sveltekit-full/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.svelte' diff --git a/sveltekit-full/src/components/editor/ui/inline-menu/inline-menu.svelte b/sveltekit-full/src/components/editor/ui/inline-menu/inline-menu.svelte deleted file mode 100644 index 989f0c013b..0000000000 --- a/sveltekit-full/src/components/editor/ui/inline-menu/inline-menu.svelte +++ /dev/null @@ -1,207 +0,0 @@ - - - { - if (!event.detail) linkMenuOpen = false - }} -> - - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.link?.canExec && $items.link} - - {/if} - - - - - { - linkMenuOpen = event.detail - }} -> - - - {#if linkMenuOpen && $items.link} -
{ - event.preventDefault() - const target = event.target as HTMLFormElement | null - const href = target?.querySelector('input')?.value?.trim() - handleLinkUpdate(href) - }} - > - -
- {/if} - {#if $items.link?.isActive} - - {/if} -
-
-
diff --git a/sveltekit-full/src/components/editor/ui/slash-menu/index.ts b/sveltekit-full/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 856d4e6b43..0000000000 --- a/sveltekit-full/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu.svelte' diff --git a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte deleted file mode 100644 index 37cea8de67..0000000000 --- a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - - No results - diff --git a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte deleted file mode 100644 index 52126eeb68..0000000000 --- a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte +++ /dev/null @@ -1,15 +0,0 @@ - - - - {props.label}{#if props.kbd}{props.kbd}{/if} - diff --git a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu.svelte b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu.svelte deleted file mode 100644 index 5da516b44f..0000000000 --- a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu.svelte +++ /dev/null @@ -1,94 +0,0 @@ - - - - - -
- $editor.commands.setParagraph()} - /> - - $editor.commands.setHeading({ level: 1 })} - /> - - $editor.commands.setHeading({ level: 2 })} - /> - - $editor.commands.setHeading({ level: 3 })} - /> - - $editor.commands.wrapInList({ kind: 'bullet' })} - /> - - $editor.commands.wrapInList({ kind: 'ordered' })} - /> - - $editor.commands.wrapInList({ kind: 'task' })} - /> - - $editor.commands.wrapInList({ kind: 'toggle' })} - /> - - $editor.commands.setBlockquote()} - /> - - $editor.commands.insertTable({ row: 3, col: 3 })} - /> - - $editor.commands.insertHorizontalRule()} - /> - - $editor.commands.setCodeBlock()} - /> - - -
-
-
-
diff --git a/sveltekit-full/src/components/editor/ui/table-handle/index.ts b/sveltekit-full/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 308cef59de..0000000000 --- a/sveltekit-full/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle.svelte' diff --git a/sveltekit-full/src/components/editor/ui/table-handle/table-handle.svelte b/sveltekit-full/src/components/editor/ui/table-handle/table-handle.svelte deleted file mode 100644 index fc91f9a438..0000000000 --- a/sveltekit-full/src/components/editor/ui/table-handle/table-handle.svelte +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - -
-
- - - {#if $state.addTableColumnBefore.canExec} - - Insert Left - - {/if} - {#if $state.addTableColumnAfter.canExec} - - Insert Right - - {/if} - {#if $state.deleteCellSelection.canExec} - - Clear Contents - Del - - {/if} - {#if $state.deleteTableColumn.canExec} - - Delete Column - - {/if} - {#if $state.deleteTable.canExec} - - Delete Table - - {/if} - - -
-
-
- - - - -
-
- - - {#if $state.addTableRowAbove.canExec} - - Insert Above - - {/if} - {#if $state.addTableRowBelow.canExec} - - Insert Below - - {/if} - {#if $state.deleteCellSelection.canExec} - - Clear Contents - Del - - {/if} - {#if $state.deleteTableRow.canExec} - - Delete Row - - {/if} - {#if $state.deleteTable.canExec} - - Delete Table - - {/if} - - -
-
-
-
diff --git a/sveltekit-full/src/components/editor/ui/tag-menu/index.ts b/sveltekit-full/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index 0884d7f5a1..0000000000 --- a/sveltekit-full/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu.svelte' diff --git a/sveltekit-full/src/components/editor/ui/tag-menu/tag-menu.svelte b/sveltekit-full/src/components/editor/ui/tag-menu/tag-menu.svelte deleted file mode 100644 index 8b9bf23f30..0000000000 --- a/sveltekit-full/src/components/editor/ui/tag-menu/tag-menu.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - - - - -
- - No results - - - {#each props.tags as tag (tag.id)} - handleTagInsert(tag.id, tag.label)} - > - #{tag.label} - - {/each} -
-
-
-
diff --git a/sveltekit-full/src/components/editor/ui/toolbar/index.ts b/sveltekit-full/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index 7b55cca073..0000000000 --- a/sveltekit-full/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.svelte' diff --git a/sveltekit-full/src/components/editor/ui/toolbar/toolbar.svelte b/sveltekit-full/src/components/editor/ui/toolbar/toolbar.svelte deleted file mode 100644 index 49bbeff5aa..0000000000 --- a/sveltekit-full/src/components/editor/ui/toolbar/toolbar.svelte +++ /dev/null @@ -1,365 +0,0 @@ - - -
- {#if $items.undo} - - {/if} - {#if $items.redo} - - {/if} - - {#if $items.bold} - - {/if} - {#if $items.italic} - - {/if} - {#if $items.underline} - - {/if} - {#if $items.strike} - - {/if} - {#if $items.code} - - {/if} - {#if $items.codeBlock} - - {/if} - {#if $items.heading1} - - {/if} - {#if $items.heading2} - - {/if} - {#if $items.heading3} - - {/if} - {#if $items.horizontalRule} - - {/if} - {#if $items.blockquote} - - {/if} - {#if $items.bulletList} - - {/if} - {#if $items.orderedList} - - {/if} - {#if $items.taskList} - - {/if} - {#if $items.toggleList} - - {/if} - {#if $items.indentList} - - {/if} - {#if $items.dedentList} - - {/if} - {#if uploader && $items.insertImage} - -
-
- {/if} -
diff --git a/sveltekit-full/src/components/editor/ui/user-menu/index.ts b/sveltekit-full/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index 7dbbd80d0e..0000000000 --- a/sveltekit-full/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu.svelte' diff --git a/sveltekit-full/src/components/editor/ui/user-menu/user-menu.svelte b/sveltekit-full/src/components/editor/ui/user-menu/user-menu.svelte deleted file mode 100644 index 5c0475d87e..0000000000 --- a/sveltekit-full/src/components/editor/ui/user-menu/user-menu.svelte +++ /dev/null @@ -1,70 +0,0 @@ - - - props.onQueryChange?.(event.detail)} - onOpenChange={(event) => props.onOpenChange?.(event.detail)} -> - - -
- - {loading ? 'Loading...' : 'No results'} - - - {#each props.users as user (user.id)} - handleUserInsert(user.id, user.name)} - > - {#if loading} - - {user.name} - - {:else} - - {user.name} - - {/if} - - {/each} -
-
-
-
diff --git a/sveltekit-full/src/lib/App.svelte b/sveltekit-full/src/lib/App.svelte deleted file mode 100644 index 30118df5d5..0000000000 --- a/sveltekit-full/src/lib/App.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/sveltekit-full/src/lib/client-only-editor.svelte b/sveltekit-full/src/lib/client-only-editor.svelte deleted file mode 100644 index 95b9bab68d..0000000000 --- a/sveltekit-full/src/lib/client-only-editor.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - - - diff --git a/sveltekit-full/src/lib/editor.svelte b/sveltekit-full/src/lib/editor.svelte deleted file mode 100644 index 7c89b545c5..0000000000 --- a/sveltekit-full/src/lib/editor.svelte +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/sveltekit-full/src/routes/+layout.svelte b/sveltekit-full/src/routes/+layout.svelte deleted file mode 100644 index 136e32e64a..0000000000 --- a/sveltekit-full/src/routes/+layout.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/sveltekit-full/src/routes/+page.svelte b/sveltekit-full/src/routes/+page.svelte deleted file mode 100644 index 590f61d80f..0000000000 --- a/sveltekit-full/src/routes/+page.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - -

Welcome to SvelteKit

-

Visit kit.svelte.dev to read the documentation

- diff --git a/sveltekit-full/static/favicon.png b/sveltekit-full/static/favicon.png deleted file mode 100644 index 825b9e65af7c104cfb07089bb28659393b4f2097..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH - - - - - ProseKit + Vanilla TypeScript - - - - - diff --git a/vanilla-minimal/package.json b/vanilla-minimal/package.json deleted file mode 100644 index 8e450c8e8e..0000000000 --- a/vanilla-minimal/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example-vanilla-minimal", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "postcss": "^8.5.14", - "tailwindcss": "^4.3.0", - "typescript": "~6.0.3", - "vite": "^8.0.13" - } -} diff --git a/vanilla-minimal/src/app.css b/vanilla-minimal/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vanilla-minimal/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vanilla-minimal/src/components/editor/examples/minimal/editor.ts b/vanilla-minimal/src/components/editor/examples/minimal/editor.ts deleted file mode 100644 index a8ca847e52..0000000000 --- a/vanilla-minimal/src/components/editor/examples/minimal/editor.ts +++ /dev/null @@ -1,22 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { defineBasicExtension } from 'prosekit/basic' -import { createEditor } from 'prosekit/core' - -export function setupVanillaEditor() { - const extension = defineBasicExtension() - const editor = createEditor({ extension }) - - return { - render: () => { - const element = document.createElement('div') - element.className = 'outline-solid p-4' - editor.mount(element) - return element - }, - destroy: () => { - editor.unmount() - }, - } -} diff --git a/vanilla-minimal/src/components/editor/examples/minimal/index.ts b/vanilla-minimal/src/components/editor/examples/minimal/index.ts deleted file mode 100644 index e54daaa4f4..0000000000 --- a/vanilla-minimal/src/components/editor/examples/minimal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { setupVanillaEditor } from './editor' diff --git a/vanilla-minimal/src/editor.ts b/vanilla-minimal/src/editor.ts deleted file mode 100644 index 3ea03142c5..0000000000 --- a/vanilla-minimal/src/editor.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { setupVanillaEditor } from './components/editor/examples/minimal' - -export function renderEditor() { - return setupVanillaEditor().render() -} diff --git a/vanilla-minimal/src/main.ts b/vanilla-minimal/src/main.ts deleted file mode 100644 index a4945ae00c..0000000000 --- a/vanilla-minimal/src/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -import './app.css' -import { renderEditor } from './editor' - -let container = document.querySelector('#app') -if (!container) { - container = document.createElement('div') - container.id = 'app' - document.body.appendChild(container) -} - -container.replaceChildren(renderEditor()) diff --git a/vanilla-minimal/tsconfig.json b/vanilla-minimal/tsconfig.json deleted file mode 100644 index 4ba8dd95cf..0000000000 --- a/vanilla-minimal/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/vanilla-minimal/vite.config.ts b/vanilla-minimal/vite.config.ts deleted file mode 100644 index fb0cdf00b5..0000000000 --- a/vanilla-minimal/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [tailwindcss()], -}) diff --git a/vanilla-slash-menu/.gitignore b/vanilla-slash-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vanilla-slash-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vanilla-slash-menu/README.md b/vanilla-slash-menu/README.md deleted file mode 100644 index 0efff88c1b..0000000000 --- a/vanilla-slash-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vanilla-slash-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vanilla-slash-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vanilla-slash-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vanilla-slash-menu vanilla-slash-menu -cd vanilla-slash-menu -npm install -npm run dev -``` diff --git a/vanilla-slash-menu/index.html b/vanilla-slash-menu/index.html deleted file mode 100644 index 2d9080a6a4..0000000000 --- a/vanilla-slash-menu/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - ProseKit + Vanilla TypeScript - - - - - diff --git a/vanilla-slash-menu/package.json b/vanilla-slash-menu/package.json deleted file mode 100644 index 4670fc8402..0000000000 --- a/vanilla-slash-menu/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example-vanilla-slash-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "postcss": "^8.5.14", - "tailwindcss": "^4.3.0", - "typescript": "~6.0.3", - "vite": "^8.0.13" - } -} diff --git a/vanilla-slash-menu/src/app.css b/vanilla-slash-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vanilla-slash-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vanilla-slash-menu/src/components/editor/examples/slash-menu/editor.ts b/vanilla-slash-menu/src/components/editor/examples/slash-menu/editor.ts deleted file mode 100644 index c0e181daa5..0000000000 --- a/vanilla-slash-menu/src/components/editor/examples/slash-menu/editor.ts +++ /dev/null @@ -1,39 +0,0 @@ -import 'prosekit/basic/style.css' -import 'prosekit/basic/typography.css' - -import { createEditor } from 'prosekit/core' - -import { renderSlashMenu } from '../../ui/slash-menu' - -import { defineExtension } from './extension' - -export function setupVanillaEditor() { - const extension = defineExtension() - const editor = createEditor({ extension }) - - return { - render: () => { - const port = document.createElement('div') - port.className = - 'box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-[canvas] text-black dark:text-white' - - const scrolling = document.createElement('div') - scrolling.className = 'relative w-full flex-1 box-border overflow-y-auto' - port.append(scrolling) - - const content = document.createElement('div') - content.className = - 'ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500' - scrolling.append(content) - - scrolling.append(renderSlashMenu(editor)) - - editor.mount(content) - - return port - }, - destroy: () => { - editor.unmount() - }, - } -} diff --git a/vanilla-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/vanilla-slash-menu/src/components/editor/examples/slash-menu/extension.ts deleted file mode 100644 index 0edda60136..0000000000 --- a/vanilla-slash-menu/src/components/editor/examples/slash-menu/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vanilla-slash-menu/src/components/editor/examples/slash-menu/index.ts b/vanilla-slash-menu/src/components/editor/examples/slash-menu/index.ts deleted file mode 100644 index e54daaa4f4..0000000000 --- a/vanilla-slash-menu/src/components/editor/examples/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { setupVanillaEditor } from './editor' diff --git a/vanilla-slash-menu/src/components/editor/ui/slash-menu/index.ts b/vanilla-slash-menu/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 862a5dee51..0000000000 --- a/vanilla-slash-menu/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { renderSlashMenu } from './slash-menu' diff --git a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts deleted file mode 100644 index cb7d6cbe45..0000000000 --- a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts +++ /dev/null @@ -1,17 +0,0 @@ -import 'prosekit/web/autocomplete' - -import type { AutocompleteEmptyElement } from 'prosekit/web/autocomplete' - -export function renderSlashMenuEmpty() { - const empty = document.createElement( - 'prosekit-autocomplete-empty', - ) as AutocompleteEmptyElement - empty.className = - 'relative flex items-center justify-between min-w-32 scroll-my-1 rounded-md px-3 py-1.5 text-sm box-border cursor-default select-none whitespace-nowrap outline-hidden data-highlighted:bg-gray-100 dark:data-highlighted:bg-gray-800' - - const span = document.createElement('span') - span.textContent = 'No results' - empty.append(span) - - return empty -} diff --git a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts deleted file mode 100644 index 4de0019bf2..0000000000 --- a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts +++ /dev/null @@ -1,29 +0,0 @@ -import 'prosekit/web/autocomplete' - -import type { AutocompleteItemElement } from 'prosekit/web/autocomplete' - -export function renderSlashMenuItem(options: { - label: string - kbd?: string - onSelect: () => void -}) { - const item = document.createElement( - 'prosekit-autocomplete-item', - ) as AutocompleteItemElement - item.className = - 'relative flex items-center justify-between min-w-32 scroll-my-1 rounded-md px-3 py-1.5 text-sm box-border cursor-default select-none whitespace-nowrap outline-hidden data-highlighted:bg-gray-100 dark:data-highlighted:bg-gray-800' - item.addEventListener('select', () => options.onSelect()) - - const span = document.createElement('span') - span.textContent = options.label - item.append(span) - - if (options.kbd) { - const kbd = document.createElement('kbd') - kbd.className = 'text-xs font-mono text-gray-400 dark:text-gray-500' - kbd.textContent = options.kbd - item.append(kbd) - } - - return item -} diff --git a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts deleted file mode 100644 index 22380d2978..0000000000 --- a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts +++ /dev/null @@ -1,131 +0,0 @@ -import 'prosekit/web/autocomplete' - -import type { BasicExtension } from 'prosekit/basic' -import type { Editor } from 'prosekit/core' -import { canUseRegexLookbehind } from 'prosekit/core' -import type { - AutocompletePopupElement, - AutocompletePositionerElement, - AutocompleteRootElement, -} from 'prosekit/web/autocomplete' - -import { renderSlashMenuEmpty } from './slash-menu-empty' -import { renderSlashMenuItem } from './slash-menu-item' - -// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". -const regex = canUseRegexLookbehind() ? /(?) { - const root = document.createElement( - 'prosekit-autocomplete-root', - ) as AutocompleteRootElement - root.editor = editor - root.regex = regex - - const positioner = document.createElement( - 'prosekit-autocomplete-positioner', - ) as AutocompletePositionerElement - positioner.className = - 'block overflow-visible w-min h-min z-50 ease-out transition-transform duration-100 motion-reduce:transition-none' - - const popup = document.createElement( - 'prosekit-autocomplete-popup', - ) as AutocompletePopupElement - popup.className = - 'box-border origin-(--transform-origin) transition-[opacity,scale] transition-discrete motion-reduce:transition-none data-[state=closed]:duration-150 data-[state=closed]:opacity-0 starting:opacity-0 data-[state=closed]:scale-95 starting:scale-95 duration-40 rounded-xl border border-gray-200 dark:border-gray-800 shadow-lg bg-[canvas] flex flex-col relative max-h-100 min-h-0 min-w-60 select-none overflow-hidden whitespace-nowrap' - - const content = document.createElement('div') - content.className = - 'flex flex-col flex-1 min-h-0 overflow-y-auto p-1 bg-[canvas] overscroll-contain' - - content.append( - renderSlashMenuItem({ - label: 'Text', - kbd: undefined, - onSelect: () => editor.commands.setParagraph(), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Heading 1', - kbd: '#', - onSelect: () => editor.commands.setHeading({ level: 1 }), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Heading 2', - kbd: '##', - onSelect: () => editor.commands.setHeading({ level: 2 }), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Heading 3', - kbd: '###', - onSelect: () => editor.commands.setHeading({ level: 3 }), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Bullet list', - kbd: '-', - onSelect: () => editor.commands.wrapInList({ kind: 'bullet' }), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Ordered list', - kbd: '1.', - onSelect: () => editor.commands.wrapInList({ kind: 'ordered' }), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Task list', - kbd: '[]', - onSelect: () => editor.commands.wrapInList({ kind: 'task' }), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Toggle list', - kbd: '>>', - onSelect: () => editor.commands.wrapInList({ kind: 'toggle' }), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Quote', - kbd: '>', - onSelect: () => editor.commands.setBlockquote(), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Table', - onSelect: () => editor.commands.insertTable({ row: 3, col: 3 }), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Divider', - kbd: '---', - onSelect: () => editor.commands.insertHorizontalRule(), - }), - ) - content.append( - renderSlashMenuItem({ - label: 'Code', - kbd: '```', - onSelect: () => editor.commands.setCodeBlock(), - }), - ) - content.append(renderSlashMenuEmpty()) - - popup.append(content) - positioner.append(popup) - root.append(positioner) - - return root -} diff --git a/vanilla-slash-menu/src/editor.ts b/vanilla-slash-menu/src/editor.ts deleted file mode 100644 index 877138feee..0000000000 --- a/vanilla-slash-menu/src/editor.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { setupVanillaEditor } from './components/editor/examples/slash-menu' - -export function renderEditor() { - return setupVanillaEditor().render() -} diff --git a/vanilla-slash-menu/src/main.ts b/vanilla-slash-menu/src/main.ts deleted file mode 100644 index a4945ae00c..0000000000 --- a/vanilla-slash-menu/src/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -import './app.css' -import { renderEditor } from './editor' - -let container = document.querySelector('#app') -if (!container) { - container = document.createElement('div') - container.id = 'app' - document.body.appendChild(container) -} - -container.replaceChildren(renderEditor()) diff --git a/vanilla-slash-menu/tsconfig.json b/vanilla-slash-menu/tsconfig.json deleted file mode 100644 index 4ba8dd95cf..0000000000 --- a/vanilla-slash-menu/tsconfig.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "types": ["vite/client"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src"] -} diff --git a/vanilla-slash-menu/vite.config.ts b/vanilla-slash-menu/vite.config.ts deleted file mode 100644 index fb0cdf00b5..0000000000 --- a/vanilla-slash-menu/vite.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'vite' -import tailwindcss from '@tailwindcss/vite' - -export default defineConfig({ - plugins: [tailwindcss()], -}) diff --git a/vue-block-handle/.gitignore b/vue-block-handle/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-block-handle/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-block-handle/README.md b/vue-block-handle/README.md deleted file mode 100644 index ec30270abe..0000000000 --- a/vue-block-handle/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-block-handle - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-block-handle) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-block-handle) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-block-handle vue-block-handle -cd vue-block-handle -npm install -npm run dev -``` diff --git a/vue-block-handle/index.html b/vue-block-handle/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-block-handle/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-block-handle/package.json b/vue-block-handle/package.json deleted file mode 100644 index bddec80eda..0000000000 --- a/vue-block-handle/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-block-handle", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-block-handle/src/App.vue b/vue-block-handle/src/App.vue deleted file mode 100644 index de7bb239b6..0000000000 --- a/vue-block-handle/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-block-handle/src/app.css b/vue-block-handle/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-block-handle/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-block-handle/src/components/editor/examples/block-handle/editor.vue b/vue-block-handle/src/components/editor/examples/block-handle/editor.vue deleted file mode 100644 index d90d9232bc..0000000000 --- a/vue-block-handle/src/components/editor/examples/block-handle/editor.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - diff --git a/vue-block-handle/src/components/editor/examples/block-handle/extension.ts b/vue-block-handle/src/components/editor/examples/block-handle/extension.ts deleted file mode 100644 index 2c6a5383ad..0000000000 --- a/vue-block-handle/src/components/editor/examples/block-handle/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union([defineBasicExtension(), defineCodeBlockView()]) -} - -export type EditorExtension = ReturnType diff --git a/vue-block-handle/src/components/editor/examples/block-handle/index.ts b/vue-block-handle/src/components/editor/examples/block-handle/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-block-handle/src/components/editor/examples/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/vue-block-handle/src/components/editor/sample/sample-doc-block-handle.ts deleted file mode 100644 index 3c6ccdc203..0000000000 --- a/vue-block-handle/src/components/editor/sample/sample-doc-block-handle.ts +++ /dev/null @@ -1,323 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Drag and Drop Demo', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Getting Started', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This paragraph can be moved above or below other blocks.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Different Block Types', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'You can drag paragraphs, headings, lists, code blocks, and more.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Lists Work Too', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This entire list can be dragged', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Individual list items stay together', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Try moving this list around', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Ordered lists also support dragging', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The numbering updates automatically', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag this list to see it in action', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Even code blocks can be moved:', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: 'javascript', - }, - content: [ - { - type: 'text', - text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Nested Content', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This blockquote can be moved as a single unit.', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested blockquotes move together with their parent.', - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Try It Yourself', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Practice by moving this paragraph to the top of the document.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Or drag this one to between the headings above.', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The drag handles make it easy to reorganize your content exactly how you want it.', - }, - ], - }, - ], -} diff --git a/vue-block-handle/src/components/editor/ui/block-handle/block-handle.vue b/vue-block-handle/src/components/editor/ui/block-handle/block-handle.vue deleted file mode 100644 index ba06a1416a..0000000000 --- a/vue-block-handle/src/components/editor/ui/block-handle/block-handle.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/vue-block-handle/src/components/editor/ui/block-handle/index.ts b/vue-block-handle/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 2c33eb5726..0000000000 --- a/vue-block-handle/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.vue' diff --git a/vue-block-handle/src/components/editor/ui/code-block-view/code-block-view.vue b/vue-block-handle/src/components/editor/ui/code-block-view/code-block-view.vue deleted file mode 100644 index e04ea8792e..0000000000 --- a/vue-block-handle/src/components/editor/ui/code-block-view/code-block-view.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/vue-block-handle/src/components/editor/ui/code-block-view/index.ts b/vue-block-handle/src/components/editor/ui/code-block-view/index.ts deleted file mode 100644 index b7beb100de..0000000000 --- a/vue-block-handle/src/components/editor/ui/code-block-view/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' - -import CodeBlockView from './code-block-view.vue' - -export function defineCodeBlockView(): Extension { - return defineVueNodeView({ - name: 'codeBlock', - contentAs: 'code', - component: CodeBlockView as VueNodeViewComponent, - }) -} diff --git a/vue-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.vue b/vue-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.vue deleted file mode 100644 index cac51a8629..0000000000 --- a/vue-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-block-handle/src/components/editor/ui/drop-indicator/index.ts b/vue-block-handle/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index b455b1217b..0000000000 --- a/vue-block-handle/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator.vue' diff --git a/vue-block-handle/src/main.ts b/vue-block-handle/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-block-handle/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-block-handle/tsconfig.app.json b/vue-block-handle/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-block-handle/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-block-handle/tsconfig.json b/vue-block-handle/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-block-handle/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-block-handle/tsconfig.node.json b/vue-block-handle/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-block-handle/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-block-handle/vite.config.ts b/vue-block-handle/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-block-handle/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-blockquote/.gitignore b/vue-blockquote/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-blockquote/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-blockquote/README.md b/vue-blockquote/README.md deleted file mode 100644 index db02e76337..0000000000 --- a/vue-blockquote/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-blockquote - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-blockquote) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-blockquote) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-blockquote vue-blockquote -cd vue-blockquote -npm install -npm run dev -``` diff --git a/vue-blockquote/index.html b/vue-blockquote/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-blockquote/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-blockquote/package.json b/vue-blockquote/package.json deleted file mode 100644 index b2f8ef7864..0000000000 --- a/vue-blockquote/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-blockquote", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-blockquote/src/App.vue b/vue-blockquote/src/App.vue deleted file mode 100644 index b931971697..0000000000 --- a/vue-blockquote/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-blockquote/src/app.css b/vue-blockquote/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-blockquote/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-blockquote/src/components/editor/examples/blockquote/editor.vue b/vue-blockquote/src/components/editor/examples/blockquote/editor.vue deleted file mode 100644 index 7d4edcece6..0000000000 --- a/vue-blockquote/src/components/editor/examples/blockquote/editor.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/vue-blockquote/src/components/editor/examples/blockquote/extension.ts b/vue-blockquote/src/components/editor/examples/blockquote/extension.ts deleted file mode 100644 index 5292b59e35..0000000000 --- a/vue-blockquote/src/components/editor/examples/blockquote/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBlockquote(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-blockquote/src/components/editor/examples/blockquote/index.ts b/vue-blockquote/src/components/editor/examples/blockquote/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-blockquote/src/components/editor/examples/blockquote/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-blockquote/src/components/editor/ui/button/button.vue b/vue-blockquote/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-blockquote/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-blockquote/src/components/editor/ui/button/index.ts b/vue-blockquote/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-blockquote/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/vue-blockquote/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-blockquote/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-blockquote/src/components/editor/ui/toolbar/index.ts b/vue-blockquote/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-blockquote/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-blockquote/src/components/editor/ui/toolbar/toolbar.vue b/vue-blockquote/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-blockquote/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-blockquote/src/main.ts b/vue-blockquote/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-blockquote/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-blockquote/tsconfig.app.json b/vue-blockquote/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-blockquote/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-blockquote/tsconfig.json b/vue-blockquote/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-blockquote/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-blockquote/tsconfig.node.json b/vue-blockquote/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-blockquote/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-blockquote/vite.config.ts b/vue-blockquote/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-blockquote/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-bold/.gitignore b/vue-bold/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-bold/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-bold/README.md b/vue-bold/README.md deleted file mode 100644 index 0d17b69b30..0000000000 --- a/vue-bold/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-bold - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-bold) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-bold) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-bold vue-bold -cd vue-bold -npm install -npm run dev -``` diff --git a/vue-bold/index.html b/vue-bold/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-bold/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-bold/package.json b/vue-bold/package.json deleted file mode 100644 index 86123b8d61..0000000000 --- a/vue-bold/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-bold", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-bold/src/App.vue b/vue-bold/src/App.vue deleted file mode 100644 index bb01967f7f..0000000000 --- a/vue-bold/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-bold/src/app.css b/vue-bold/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-bold/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-bold/src/components/editor/examples/bold/editor.vue b/vue-bold/src/components/editor/examples/bold/editor.vue deleted file mode 100644 index 2987d333aa..0000000000 --- a/vue-bold/src/components/editor/examples/bold/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-bold/src/components/editor/examples/bold/extension.ts b/vue-bold/src/components/editor/examples/bold/extension.ts deleted file mode 100644 index eaa4fba721..0000000000 --- a/vue-bold/src/components/editor/examples/bold/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineBold } from 'prosekit/extensions/bold' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineBold(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-bold/src/components/editor/examples/bold/index.ts b/vue-bold/src/components/editor/examples/bold/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-bold/src/components/editor/examples/bold/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-bold/src/components/editor/sample/sample-doc-bold.ts b/vue-bold/src/components/editor/sample/sample-doc-bold.ts deleted file mode 100644 index 09ed08daad..0000000000 --- a/vue-bold/src/components/editor/sample/sample-doc-bold.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'This is bold too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/vue-bold/src/components/editor/ui/button/button.vue b/vue-bold/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-bold/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-bold/src/components/editor/ui/button/index.ts b/vue-bold/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-bold/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-bold/src/components/editor/ui/image-upload-popover/index.ts b/vue-bold/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-bold/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-bold/src/components/editor/ui/toolbar/index.ts b/vue-bold/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-bold/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-bold/src/components/editor/ui/toolbar/toolbar.vue b/vue-bold/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-bold/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-bold/src/main.ts b/vue-bold/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-bold/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-bold/tsconfig.app.json b/vue-bold/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-bold/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-bold/tsconfig.json b/vue-bold/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-bold/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-bold/tsconfig.node.json b/vue-bold/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-bold/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-bold/vite.config.ts b/vue-bold/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-bold/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-change-tracking/.gitignore b/vue-change-tracking/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-change-tracking/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-change-tracking/README.md b/vue-change-tracking/README.md deleted file mode 100644 index 0ca20f42f9..0000000000 --- a/vue-change-tracking/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-change-tracking - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-change-tracking) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-change-tracking) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-change-tracking vue-change-tracking -cd vue-change-tracking -npm install -npm run dev -``` diff --git a/vue-change-tracking/index.html b/vue-change-tracking/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-change-tracking/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-change-tracking/package.json b/vue-change-tracking/package.json deleted file mode 100644 index 35550fcd79..0000000000 --- a/vue-change-tracking/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-change-tracking", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-change-tracking/src/App.vue b/vue-change-tracking/src/App.vue deleted file mode 100644 index 6d4c9d0394..0000000000 --- a/vue-change-tracking/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-change-tracking/src/app.css b/vue-change-tracking/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-change-tracking/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-change-tracking/src/components/editor/examples/change-tracking/editor-diff.vue b/vue-change-tracking/src/components/editor/examples/change-tracking/editor-diff.vue deleted file mode 100644 index 8825343c7e..0000000000 --- a/vue-change-tracking/src/components/editor/examples/change-tracking/editor-diff.vue +++ /dev/null @@ -1,32 +0,0 @@ - - - diff --git a/vue-change-tracking/src/components/editor/examples/change-tracking/editor-main.vue b/vue-change-tracking/src/components/editor/examples/change-tracking/editor-main.vue deleted file mode 100644 index 93724a8157..0000000000 --- a/vue-change-tracking/src/components/editor/examples/change-tracking/editor-main.vue +++ /dev/null @@ -1,40 +0,0 @@ - - - diff --git a/vue-change-tracking/src/components/editor/examples/change-tracking/editor.vue b/vue-change-tracking/src/components/editor/examples/change-tracking/editor.vue deleted file mode 100644 index 08d3bb77d9..0000000000 --- a/vue-change-tracking/src/components/editor/examples/change-tracking/editor.vue +++ /dev/null @@ -1,71 +0,0 @@ - - - diff --git a/vue-change-tracking/src/components/editor/examples/change-tracking/index.ts b/vue-change-tracking/src/components/editor/examples/change-tracking/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-change-tracking/src/components/editor/examples/change-tracking/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-change-tracking/src/main.ts b/vue-change-tracking/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-change-tracking/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-change-tracking/tsconfig.app.json b/vue-change-tracking/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-change-tracking/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-change-tracking/tsconfig.json b/vue-change-tracking/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-change-tracking/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-change-tracking/tsconfig.node.json b/vue-change-tracking/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-change-tracking/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-change-tracking/vite.config.ts b/vue-change-tracking/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-change-tracking/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-code-block-themes/.gitignore b/vue-code-block-themes/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-code-block-themes/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-code-block-themes/README.md b/vue-code-block-themes/README.md deleted file mode 100644 index b7662cb7dc..0000000000 --- a/vue-code-block-themes/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-code-block-themes - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-code-block-themes) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-code-block-themes) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-code-block-themes vue-code-block-themes -cd vue-code-block-themes -npm install -npm run dev -``` diff --git a/vue-code-block-themes/index.html b/vue-code-block-themes/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-code-block-themes/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-code-block-themes/package.json b/vue-code-block-themes/package.json deleted file mode 100644 index 875dde166c..0000000000 --- a/vue-code-block-themes/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-code-block-themes", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-code-block-themes/src/App.vue b/vue-code-block-themes/src/App.vue deleted file mode 100644 index 4c1eff8f81..0000000000 --- a/vue-code-block-themes/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-code-block-themes/src/app.css b/vue-code-block-themes/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-code-block-themes/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/editor.vue b/vue-code-block-themes/src/components/editor/examples/code-block-themes/editor.vue deleted file mode 100644 index 447334d101..0000000000 --- a/vue-code-block-themes/src/components/editor/examples/code-block-themes/editor.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/vue-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts deleted file mode 100644 index b5686b8c04..0000000000 --- a/vue-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union(defineBasicExtension(), defineCodeBlockView()) -} - -export type EditorExtension = ReturnType diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/vue-code-block-themes/src/components/editor/examples/code-block-themes/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-code-block-themes/src/components/editor/examples/code-block-themes/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.vue b/vue-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.vue deleted file mode 100644 index d248f3115e..0000000000 --- a/vue-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.vue b/vue-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.vue deleted file mode 100644 index 3d86fafb76..0000000000 --- a/vue-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/vue-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/vue-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/vue-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/vue-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.vue b/vue-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.vue deleted file mode 100644 index e04ea8792e..0000000000 --- a/vue-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/vue-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/vue-code-block-themes/src/components/editor/ui/code-block-view/index.ts deleted file mode 100644 index b7beb100de..0000000000 --- a/vue-code-block-themes/src/components/editor/ui/code-block-view/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' - -import CodeBlockView from './code-block-view.vue' - -export function defineCodeBlockView(): Extension { - return defineVueNodeView({ - name: 'codeBlock', - contentAs: 'code', - component: CodeBlockView as VueNodeViewComponent, - }) -} diff --git a/vue-code-block-themes/src/main.ts b/vue-code-block-themes/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-code-block-themes/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-code-block-themes/tsconfig.app.json b/vue-code-block-themes/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-code-block-themes/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-code-block-themes/tsconfig.json b/vue-code-block-themes/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-code-block-themes/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-code-block-themes/tsconfig.node.json b/vue-code-block-themes/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-code-block-themes/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-code-block-themes/vite.config.ts b/vue-code-block-themes/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-code-block-themes/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-code-block/.gitignore b/vue-code-block/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-code-block/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-code-block/README.md b/vue-code-block/README.md deleted file mode 100644 index f369822592..0000000000 --- a/vue-code-block/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-code-block - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-code-block) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-code-block) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-code-block vue-code-block -cd vue-code-block -npm install -npm run dev -``` diff --git a/vue-code-block/index.html b/vue-code-block/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-code-block/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-code-block/package.json b/vue-code-block/package.json deleted file mode 100644 index 6452d01fc5..0000000000 --- a/vue-code-block/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-code-block", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-code-block/src/App.vue b/vue-code-block/src/App.vue deleted file mode 100644 index 9df9382264..0000000000 --- a/vue-code-block/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-code-block/src/app.css b/vue-code-block/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-code-block/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-code-block/src/components/editor/examples/code-block/editor.vue b/vue-code-block/src/components/editor/examples/code-block/editor.vue deleted file mode 100644 index 732a47de8b..0000000000 --- a/vue-code-block/src/components/editor/examples/code-block/editor.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/vue-code-block/src/components/editor/examples/code-block/extension.ts b/vue-code-block/src/components/editor/examples/code-block/extension.ts deleted file mode 100644 index 099cacf03b..0000000000 --- a/vue-code-block/src/components/editor/examples/code-block/extension.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { - defineCodeBlock, - defineCodeBlockShiki, -} from 'prosekit/extensions/code-block' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -import { defineCodeBlockView } from '../../ui/code-block-view' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCodeBlock(), - defineCodeBlockShiki(), - defineCodeBlockView(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-code-block/src/components/editor/examples/code-block/index.ts b/vue-code-block/src/components/editor/examples/code-block/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-code-block/src/components/editor/examples/code-block/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-code-block/src/components/editor/sample/sample-doc-code-block.ts b/vue-code-block/src/components/editor/sample/sample-doc-code-block.ts deleted file mode 100644 index dc3c3020e4..0000000000 --- a/vue-code-block/src/components/editor/sample/sample-doc-code-block.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const js = ` -async function start() { - while (true) { - await sleep() - await eat() - await code('JavaScript!') - } -} -`.trim() - -const py = ` -async def start(): - while True: - await sleep() - await eat() - await code('Python!') -`.trim() - -const go = ` -func start() { - for { - sleep() - eat() - code('Go!') - } -} -`.trim() - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [{ type: 'text', text: js }], - }, - { - type: 'codeBlock', - attrs: { language: 'python' }, - content: [{ type: 'text', text: py }], - }, - { - type: 'codeBlock', - attrs: { language: 'go' }, - content: [{ type: 'text', text: go }], - }, - ], -} diff --git a/vue-code-block/src/components/editor/ui/button/button.vue b/vue-code-block/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-code-block/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-code-block/src/components/editor/ui/button/index.ts b/vue-code-block/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-code-block/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-code-block/src/components/editor/ui/code-block-view/code-block-view.vue b/vue-code-block/src/components/editor/ui/code-block-view/code-block-view.vue deleted file mode 100644 index e04ea8792e..0000000000 --- a/vue-code-block/src/components/editor/ui/code-block-view/code-block-view.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/vue-code-block/src/components/editor/ui/code-block-view/index.ts b/vue-code-block/src/components/editor/ui/code-block-view/index.ts deleted file mode 100644 index b7beb100de..0000000000 --- a/vue-code-block/src/components/editor/ui/code-block-view/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' - -import CodeBlockView from './code-block-view.vue' - -export function defineCodeBlockView(): Extension { - return defineVueNodeView({ - name: 'codeBlock', - contentAs: 'code', - component: CodeBlockView as VueNodeViewComponent, - }) -} diff --git a/vue-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-code-block/src/components/editor/ui/image-upload-popover/index.ts b/vue-code-block/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-code-block/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-code-block/src/components/editor/ui/toolbar/index.ts b/vue-code-block/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-code-block/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-code-block/src/components/editor/ui/toolbar/toolbar.vue b/vue-code-block/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-code-block/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-code-block/src/main.ts b/vue-code-block/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-code-block/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-code-block/tsconfig.app.json b/vue-code-block/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-code-block/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-code-block/tsconfig.json b/vue-code-block/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-code-block/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-code-block/tsconfig.node.json b/vue-code-block/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-code-block/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-code-block/vite.config.ts b/vue-code-block/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-code-block/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-code/.gitignore b/vue-code/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-code/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-code/README.md b/vue-code/README.md deleted file mode 100644 index 4dc6dfc31e..0000000000 --- a/vue-code/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-code - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-code) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-code) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-code vue-code -cd vue-code -npm install -npm run dev -``` diff --git a/vue-code/index.html b/vue-code/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-code/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-code/package.json b/vue-code/package.json deleted file mode 100644 index 3fbec58fa3..0000000000 --- a/vue-code/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-code", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-code/src/App.vue b/vue-code/src/App.vue deleted file mode 100644 index debe2e237b..0000000000 --- a/vue-code/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-code/src/app.css b/vue-code/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-code/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-code/src/components/editor/examples/code/editor.vue b/vue-code/src/components/editor/examples/code/editor.vue deleted file mode 100644 index c0b860042b..0000000000 --- a/vue-code/src/components/editor/examples/code/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-code/src/components/editor/examples/code/extension.ts b/vue-code/src/components/editor/examples/code/extension.ts deleted file mode 100644 index e9e273216e..0000000000 --- a/vue-code/src/components/editor/examples/code/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineCode(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-code/src/components/editor/examples/code/index.ts b/vue-code/src/components/editor/examples/code/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-code/src/components/editor/examples/code/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-code/src/components/editor/sample/sample-doc-code.ts b/vue-code/src/components/editor/sample/sample-doc-code.ts deleted file mode 100644 index 2fdbcee1f3..0000000000 --- a/vue-code/src/components/editor/sample/sample-doc-code.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'This is code', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/vue-code/src/components/editor/ui/button/button.vue b/vue-code/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-code/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-code/src/components/editor/ui/button/index.ts b/vue-code/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-code/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-code/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-code/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-code/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-code/src/components/editor/ui/image-upload-popover/index.ts b/vue-code/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-code/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-code/src/components/editor/ui/toolbar/index.ts b/vue-code/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-code/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-code/src/components/editor/ui/toolbar/toolbar.vue b/vue-code/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-code/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-code/src/main.ts b/vue-code/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-code/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-code/tsconfig.app.json b/vue-code/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-code/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-code/tsconfig.json b/vue-code/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-code/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-code/tsconfig.node.json b/vue-code/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-code/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-code/vite.config.ts b/vue-code/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-code/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-drop-cursor/.gitignore b/vue-drop-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-drop-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-drop-cursor/README.md b/vue-drop-cursor/README.md deleted file mode 100644 index 229ed15f7a..0000000000 --- a/vue-drop-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-drop-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-drop-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-drop-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-drop-cursor vue-drop-cursor -cd vue-drop-cursor -npm install -npm run dev -``` diff --git a/vue-drop-cursor/index.html b/vue-drop-cursor/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-drop-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-drop-cursor/package.json b/vue-drop-cursor/package.json deleted file mode 100644 index 1676093f1a..0000000000 --- a/vue-drop-cursor/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-drop-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-drop-cursor/src/App.vue b/vue-drop-cursor/src/App.vue deleted file mode 100644 index 14188942fc..0000000000 --- a/vue-drop-cursor/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-drop-cursor/src/app.css b/vue-drop-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-drop-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-drop-cursor/src/components/editor/examples/drop-cursor/editor.vue b/vue-drop-cursor/src/components/editor/examples/drop-cursor/editor.vue deleted file mode 100644 index 1ac7fc47f3..0000000000 --- a/vue-drop-cursor/src/components/editor/examples/drop-cursor/editor.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/vue-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/vue-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts deleted file mode 100644 index fd79a2c96c..0000000000 --- a/vue-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineImage(), - defineDropCursor({ - color: false, - width: 4, - class: 'transition-all bg-blue-500', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/vue-drop-cursor/src/components/editor/examples/drop-cursor/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-drop-cursor/src/components/editor/examples/drop-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/vue-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts deleted file mode 100644 index 22c6b93465..0000000000 --- a/vue-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the images below to see the custom drop cursor.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/320x240/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/green/320x240/40', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blue/320x240/187', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/red/320x240/188', - }, - }, - ], -} diff --git a/vue-drop-cursor/src/main.ts b/vue-drop-cursor/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-drop-cursor/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-drop-cursor/tsconfig.app.json b/vue-drop-cursor/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-drop-cursor/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-drop-cursor/tsconfig.json b/vue-drop-cursor/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-drop-cursor/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-drop-cursor/tsconfig.node.json b/vue-drop-cursor/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-drop-cursor/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-drop-cursor/vite.config.ts b/vue-drop-cursor/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-drop-cursor/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-emoji-rules/.gitignore b/vue-emoji-rules/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-emoji-rules/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-emoji-rules/README.md b/vue-emoji-rules/README.md deleted file mode 100644 index a47eaa9016..0000000000 --- a/vue-emoji-rules/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-emoji-rules - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-emoji-rules) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-emoji-rules) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-emoji-rules vue-emoji-rules -cd vue-emoji-rules -npm install -npm run dev -``` diff --git a/vue-emoji-rules/index.html b/vue-emoji-rules/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-emoji-rules/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-emoji-rules/package.json b/vue-emoji-rules/package.json deleted file mode 100644 index 880cf6cc37..0000000000 --- a/vue-emoji-rules/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-emoji-rules", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-emoji-rules/src/App.vue b/vue-emoji-rules/src/App.vue deleted file mode 100644 index c88e4f810f..0000000000 --- a/vue-emoji-rules/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-emoji-rules/src/app.css b/vue-emoji-rules/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-emoji-rules/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-emoji-rules/src/components/editor/examples/emoji-rules/editor.vue b/vue-emoji-rules/src/components/editor/examples/emoji-rules/editor.vue deleted file mode 100644 index d8707ded7c..0000000000 --- a/vue-emoji-rules/src/components/editor/examples/emoji-rules/editor.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/vue-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/vue-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts deleted file mode 100644 index 5cac9cbc79..0000000000 --- a/vue-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineEnterRule } from 'prosekit/extensions/enter-rule' - -/** - * Converts the text before the text cursor into an emoji when pressing `Enter`. - */ -export function defineEmojiEnterRule() { - return defineEnterRule({ - regex: /:(apple|banana):$/, - handler: ({ match, from, to, state }) => { - const text = match[1] as 'apple' | 'banana' - const emoji = text === 'apple' ? '🍎' : '🍌' - return state.tr.replaceWith(from, to, state.schema.text(emoji)) - }, - }) -} diff --git a/vue-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/vue-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts deleted file mode 100644 index bc9bcb8412..0000000000 --- a/vue-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { defineEmojiEnterRule } from './emoji' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineEmojiEnterRule(), - definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/vue-emoji-rules/src/components/editor/examples/emoji-rules/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-emoji-rules/src/components/editor/examples/emoji-rules/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-emoji-rules/src/main.ts b/vue-emoji-rules/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-emoji-rules/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-emoji-rules/tsconfig.app.json b/vue-emoji-rules/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-emoji-rules/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-emoji-rules/tsconfig.json b/vue-emoji-rules/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-emoji-rules/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-emoji-rules/tsconfig.node.json b/vue-emoji-rules/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-emoji-rules/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-emoji-rules/vite.config.ts b/vue-emoji-rules/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-emoji-rules/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-full/.gitignore b/vue-full/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-full/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-full/README.md b/vue-full/README.md deleted file mode 100644 index ac4740405a..0000000000 --- a/vue-full/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-full - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-full) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-full) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-full vue-full -cd vue-full -npm install -npm run dev -``` diff --git a/vue-full/index.html b/vue-full/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-full/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-full/package.json b/vue-full/package.json deleted file mode 100644 index 3acc70a54e..0000000000 --- a/vue-full/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-vue-full", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-full/src/App.vue b/vue-full/src/App.vue deleted file mode 100644 index 560ed9299f..0000000000 --- a/vue-full/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-full/src/app.css b/vue-full/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-full/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-full/src/components/editor/examples/full/editor.vue b/vue-full/src/components/editor/examples/full/editor.vue deleted file mode 100644 index a81ba14ef8..0000000000 --- a/vue-full/src/components/editor/examples/full/editor.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/examples/full/extension.ts b/vue-full/src/components/editor/examples/full/extension.ts deleted file mode 100644 index 5fc2f60685..0000000000 --- a/vue-full/src/components/editor/examples/full/extension.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineImageUploadHandler } from 'prosekit/extensions/image' -import { defineMath } from 'prosekit/extensions/math' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' -import { sampleUploader } from '../../sample/sample-uploader' -import { defineCodeBlockView } from '../../ui/code-block-view' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - defineMention(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - defineCodeBlockShiki(), - defineHorizontalRule(), - defineCodeBlockView(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-full/src/components/editor/examples/full/index.ts b/vue-full/src/components/editor/examples/full/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-full/src/components/editor/examples/full/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-full/src/components/editor/sample/katex.ts b/vue-full/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/vue-full/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/vue-full/src/components/editor/sample/sample-doc-full.ts b/vue-full/src/components/editor/sample/sample-doc-full.ts deleted file mode 100644 index 13e49b634d..0000000000 --- a/vue-full/src/components/editor/sample/sample-doc-full.ts +++ /dev/null @@ -1,442 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'The editor that thinks like you' }], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', - }, - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'writing without barriers', - }, - { type: 'text', text: '.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Text that shines.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Make your words ' }, - { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, - { type: 'text', text: ', ' }, - { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, - { type: 'text', text: ', or ' }, - { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, - { type: 'text', text: '. Add ' }, - { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, - { type: 'text', text: ' that stands out. Create ' }, - { - type: 'text', - marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], - text: 'links', - }, - { type: 'text', text: ' that connect.' }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Select any text to format it. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '@' }, - { type: 'text', text: ' to mention ' }, - { - type: 'mention', - attrs: { id: '39', value: '@someone', kind: 'user' }, - }, - { type: 'text', text: ' or ' }, - { type: 'text', marks: [{ type: 'code' }], text: '#' }, - { type: 'text', text: ' for ' }, - { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, - { type: 'text', text: '. Press ' }, - { type: 'text', marks: [{ type: 'code' }], text: '/' }, - { type: 'text', text: " and discover what's possible." }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Lists that organize.' }], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Bullet points that guide thoughts' }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Nested lists for complex ideas' }], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sub-points flow naturally' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Tasks that focus' }], - }, - { - type: 'list', - attrs: { kind: 'task', order: null, checked: true, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Done feels good' }], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Todo drives action' }], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Numbered steps' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Sequential thinking' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Clear progress' }], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Code that inspires.' }], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Images that captivate.' }], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/season/320x240/107', - }, - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Drag the handle in the bottom right corner to resize.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Tables that structure.' }], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'Feature', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [{ type: 'bold' }], - text: 'How to use', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Format text' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Select and choose' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Perfect styling' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Add mentions' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Type @ and name' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Connected ideas' }], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Insert anything' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Press / for menu' }], - }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Endless possibilities' }], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Math that renders.' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Inline math like ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' appears within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Quotes that inspire.' }], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: '"This is not just an editor. This is how writing should feel."', - }, - ], - }, - ], - }, - { type: 'horizontalRule' }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Start typing. Everything else just flows.' }, - ], - }, - ], -} diff --git a/vue-full/src/components/editor/sample/sample-tag-data.ts b/vue-full/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/vue-full/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/vue-full/src/components/editor/sample/sample-uploader.ts b/vue-full/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/vue-full/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/vue-full/src/components/editor/sample/sample-user-data.ts b/vue-full/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/vue-full/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/vue-full/src/components/editor/ui/block-handle/block-handle.vue b/vue-full/src/components/editor/ui/block-handle/block-handle.vue deleted file mode 100644 index ba06a1416a..0000000000 --- a/vue-full/src/components/editor/ui/block-handle/block-handle.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/block-handle/index.ts b/vue-full/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 2c33eb5726..0000000000 --- a/vue-full/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.vue' diff --git a/vue-full/src/components/editor/ui/button/button.vue b/vue-full/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-full/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/button/index.ts b/vue-full/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-full/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-full/src/components/editor/ui/code-block-view/code-block-view.vue b/vue-full/src/components/editor/ui/code-block-view/code-block-view.vue deleted file mode 100644 index e04ea8792e..0000000000 --- a/vue-full/src/components/editor/ui/code-block-view/code-block-view.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/code-block-view/index.ts b/vue-full/src/components/editor/ui/code-block-view/index.ts deleted file mode 100644 index b7beb100de..0000000000 --- a/vue-full/src/components/editor/ui/code-block-view/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' - -import CodeBlockView from './code-block-view.vue' - -export function defineCodeBlockView(): Extension { - return defineVueNodeView({ - name: 'codeBlock', - contentAs: 'code', - component: CodeBlockView as VueNodeViewComponent, - }) -} diff --git a/vue-full/src/components/editor/ui/drop-indicator/drop-indicator.vue b/vue-full/src/components/editor/ui/drop-indicator/drop-indicator.vue deleted file mode 100644 index cac51a8629..0000000000 --- a/vue-full/src/components/editor/ui/drop-indicator/drop-indicator.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/drop-indicator/index.ts b/vue-full/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index b455b1217b..0000000000 --- a/vue-full/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator.vue' diff --git a/vue-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/image-upload-popover/index.ts b/vue-full/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-full/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-full/src/components/editor/ui/image-view/image-view.vue b/vue-full/src/components/editor/ui/image-view/image-view.vue deleted file mode 100644 index a8beb8acd2..0000000000 --- a/vue-full/src/components/editor/ui/image-view/image-view.vue +++ /dev/null @@ -1,97 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/image-view/index.ts b/vue-full/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index 960e2c64d6..0000000000 --- a/vue-full/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' - -import ImageView from './image-view.vue' - -export function defineImageView(): Extension { - return defineVueNodeView({ - name: 'image', - component: ImageView as VueNodeViewComponent, - }) -} diff --git a/vue-full/src/components/editor/ui/inline-menu/index.ts b/vue-full/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8c72e460c8..0000000000 --- a/vue-full/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-full/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-full/src/components/editor/ui/inline-menu/inline-menu.vue deleted file mode 100644 index cacb76b189..0000000000 --- a/vue-full/src/components/editor/ui/inline-menu/inline-menu.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/slash-menu/index.ts b/vue-full/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 32d71d61f5..0000000000 --- a/vue-full/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu.vue' diff --git a/vue-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue b/vue-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue deleted file mode 100644 index 50fc5468fb..0000000000 --- a/vue-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/slash-menu/slash-menu-item.vue b/vue-full/src/components/editor/ui/slash-menu/slash-menu-item.vue deleted file mode 100644 index 2d99363b45..0000000000 --- a/vue-full/src/components/editor/ui/slash-menu/slash-menu-item.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/slash-menu/slash-menu.vue b/vue-full/src/components/editor/ui/slash-menu/slash-menu.vue deleted file mode 100644 index 87090511e3..0000000000 --- a/vue-full/src/components/editor/ui/slash-menu/slash-menu.vue +++ /dev/null @@ -1,106 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/table-handle/index.ts b/vue-full/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 0132b96b36..0000000000 --- a/vue-full/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle.vue' diff --git a/vue-full/src/components/editor/ui/table-handle/table-handle.vue b/vue-full/src/components/editor/ui/table-handle/table-handle.vue deleted file mode 100644 index a9921a8f37..0000000000 --- a/vue-full/src/components/editor/ui/table-handle/table-handle.vue +++ /dev/null @@ -1,204 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/tag-menu/index.ts b/vue-full/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index 6cb07b1d1c..0000000000 --- a/vue-full/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu.vue' diff --git a/vue-full/src/components/editor/ui/tag-menu/tag-menu.vue b/vue-full/src/components/editor/ui/tag-menu/tag-menu.vue deleted file mode 100644 index a8928c53a9..0000000000 --- a/vue-full/src/components/editor/ui/tag-menu/tag-menu.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/toolbar/index.ts b/vue-full/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-full/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-full/src/components/editor/ui/toolbar/toolbar.vue b/vue-full/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-full/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-full/src/components/editor/ui/user-menu/index.ts b/vue-full/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index 29fde1b0b4..0000000000 --- a/vue-full/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu.vue' diff --git a/vue-full/src/components/editor/ui/user-menu/user-menu.vue b/vue-full/src/components/editor/ui/user-menu/user-menu.vue deleted file mode 100644 index 60b4c3131c..0000000000 --- a/vue-full/src/components/editor/ui/user-menu/user-menu.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - diff --git a/vue-full/src/main.ts b/vue-full/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-full/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-full/tsconfig.app.json b/vue-full/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-full/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-full/tsconfig.json b/vue-full/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-full/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-full/tsconfig.node.json b/vue-full/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-full/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-full/vite.config.ts b/vue-full/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-full/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-gap-cursor/.gitignore b/vue-gap-cursor/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-gap-cursor/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-gap-cursor/README.md b/vue-gap-cursor/README.md deleted file mode 100644 index 9a5bc280fb..0000000000 --- a/vue-gap-cursor/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-gap-cursor - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-gap-cursor) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-gap-cursor) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-gap-cursor vue-gap-cursor -cd vue-gap-cursor -npm install -npm run dev -``` diff --git a/vue-gap-cursor/index.html b/vue-gap-cursor/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-gap-cursor/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-gap-cursor/package.json b/vue-gap-cursor/package.json deleted file mode 100644 index a829a18ff3..0000000000 --- a/vue-gap-cursor/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-gap-cursor", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-gap-cursor/src/App.vue b/vue-gap-cursor/src/App.vue deleted file mode 100644 index 9ba97a0e0c..0000000000 --- a/vue-gap-cursor/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-gap-cursor/src/app.css b/vue-gap-cursor/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-gap-cursor/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-gap-cursor/src/components/editor/examples/gap-cursor/editor.vue b/vue-gap-cursor/src/components/editor/examples/gap-cursor/editor.vue deleted file mode 100644 index 021cf9d82f..0000000000 --- a/vue-gap-cursor/src/components/editor/examples/gap-cursor/editor.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/vue-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/vue-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts deleted file mode 100644 index 599497170d..0000000000 --- a/vue-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineImage } from 'prosekit/extensions/image' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineGapCursor(), - defineImage(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/vue-gap-cursor/src/components/editor/examples/gap-cursor/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-gap-cursor/src/components/editor/examples/gap-cursor/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/vue-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts deleted file mode 100644 index e40ee2a83b..0000000000 --- a/vue-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/minimal/320x180/42', - }, - }, - ], -} diff --git a/vue-gap-cursor/src/main.ts b/vue-gap-cursor/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-gap-cursor/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-gap-cursor/tsconfig.app.json b/vue-gap-cursor/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-gap-cursor/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-gap-cursor/tsconfig.json b/vue-gap-cursor/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-gap-cursor/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-gap-cursor/tsconfig.node.json b/vue-gap-cursor/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-gap-cursor/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-gap-cursor/vite.config.ts b/vue-gap-cursor/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-gap-cursor/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-hard-break/.gitignore b/vue-hard-break/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-hard-break/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-hard-break/README.md b/vue-hard-break/README.md deleted file mode 100644 index 00b5e0a802..0000000000 --- a/vue-hard-break/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-hard-break - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-hard-break) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-hard-break) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-hard-break vue-hard-break -cd vue-hard-break -npm install -npm run dev -``` diff --git a/vue-hard-break/index.html b/vue-hard-break/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-hard-break/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-hard-break/package.json b/vue-hard-break/package.json deleted file mode 100644 index 32b17e1763..0000000000 --- a/vue-hard-break/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-hard-break", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-hard-break/src/App.vue b/vue-hard-break/src/App.vue deleted file mode 100644 index c7d9603a71..0000000000 --- a/vue-hard-break/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-hard-break/src/app.css b/vue-hard-break/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-hard-break/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-hard-break/src/components/editor/examples/hard-break/editor.vue b/vue-hard-break/src/components/editor/examples/hard-break/editor.vue deleted file mode 100644 index 89775668b2..0000000000 --- a/vue-hard-break/src/components/editor/examples/hard-break/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-hard-break/src/components/editor/examples/hard-break/extension.ts b/vue-hard-break/src/components/editor/examples/hard-break/extension.ts deleted file mode 100644 index cad2881056..0000000000 --- a/vue-hard-break/src/components/editor/examples/hard-break/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHardBreak } from 'prosekit/extensions/hard-break' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHardBreak(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-hard-break/src/components/editor/examples/hard-break/index.ts b/vue-hard-break/src/components/editor/examples/hard-break/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-hard-break/src/components/editor/examples/hard-break/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-hard-break/src/components/editor/examples/hard-break/toolbar.vue b/vue-hard-break/src/components/editor/examples/hard-break/toolbar.vue deleted file mode 100644 index 400e6c2967..0000000000 --- a/vue-hard-break/src/components/editor/examples/hard-break/toolbar.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - diff --git a/vue-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/vue-hard-break/src/components/editor/sample/sample-doc-hard-break.ts deleted file mode 100644 index e1c9786b72..0000000000 --- a/vue-hard-break/src/components/editor/sample/sample-doc-hard-break.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: "O'er all the hilltops", - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Is quiet now,', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'In all the treetops', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hearest thou', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Hardly a breath;', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'The birds are asleep in the trees:', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Wait, soon like these', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'Thou too shalt rest.', - }, - { - type: 'hardBreak', - }, - ], - }, - ], -} diff --git a/vue-hard-break/src/components/editor/ui/button/button.vue b/vue-hard-break/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-hard-break/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-hard-break/src/components/editor/ui/button/index.ts b/vue-hard-break/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-hard-break/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-hard-break/src/main.ts b/vue-hard-break/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-hard-break/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-hard-break/tsconfig.app.json b/vue-hard-break/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-hard-break/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-hard-break/tsconfig.json b/vue-hard-break/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-hard-break/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-hard-break/tsconfig.node.json b/vue-hard-break/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-hard-break/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-hard-break/vite.config.ts b/vue-hard-break/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-hard-break/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-heading/.gitignore b/vue-heading/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-heading/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-heading/README.md b/vue-heading/README.md deleted file mode 100644 index d41728fca0..0000000000 --- a/vue-heading/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-heading - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-heading) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-heading) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-heading vue-heading -cd vue-heading -npm install -npm run dev -``` diff --git a/vue-heading/index.html b/vue-heading/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-heading/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-heading/package.json b/vue-heading/package.json deleted file mode 100644 index ed80f16985..0000000000 --- a/vue-heading/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-heading", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-heading/src/App.vue b/vue-heading/src/App.vue deleted file mode 100644 index 9afe66706f..0000000000 --- a/vue-heading/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-heading/src/app.css b/vue-heading/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-heading/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-heading/src/components/editor/examples/heading/editor.vue b/vue-heading/src/components/editor/examples/heading/editor.vue deleted file mode 100644 index 7a5f02b51a..0000000000 --- a/vue-heading/src/components/editor/examples/heading/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-heading/src/components/editor/examples/heading/extension.ts b/vue-heading/src/components/editor/examples/heading/extension.ts deleted file mode 100644 index e4f8e6ace0..0000000000 --- a/vue-heading/src/components/editor/examples/heading/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHeading(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-heading/src/components/editor/examples/heading/index.ts b/vue-heading/src/components/editor/examples/heading/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-heading/src/components/editor/examples/heading/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-heading/src/components/editor/sample/sample-doc-heading.ts b/vue-heading/src/components/editor/sample/sample-doc-heading.ts deleted file mode 100644 index 210497e633..0000000000 --- a/vue-heading/src/components/editor/sample/sample-doc-heading.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'H1' }], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'H2' }], - }, - { - type: 'heading', - attrs: { level: 3 }, - content: [{ type: 'text', text: 'H3' }], - }, - { type: 'paragraph', content: [] }, - ], -} diff --git a/vue-heading/src/components/editor/ui/button/button.vue b/vue-heading/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-heading/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-heading/src/components/editor/ui/button/index.ts b/vue-heading/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-heading/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-heading/src/components/editor/ui/image-upload-popover/index.ts b/vue-heading/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-heading/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-heading/src/components/editor/ui/toolbar/index.ts b/vue-heading/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-heading/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-heading/src/components/editor/ui/toolbar/toolbar.vue b/vue-heading/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-heading/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-heading/src/main.ts b/vue-heading/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-heading/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-heading/tsconfig.app.json b/vue-heading/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-heading/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-heading/tsconfig.json b/vue-heading/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-heading/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-heading/tsconfig.node.json b/vue-heading/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-heading/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-heading/vite.config.ts b/vue-heading/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-heading/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-highlight/.gitignore b/vue-highlight/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-highlight/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-highlight/README.md b/vue-highlight/README.md deleted file mode 100644 index 1d8b925785..0000000000 --- a/vue-highlight/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-highlight - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-highlight) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-highlight) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-highlight vue-highlight -cd vue-highlight -npm install -npm run dev -``` diff --git a/vue-highlight/index.html b/vue-highlight/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-highlight/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-highlight/package.json b/vue-highlight/package.json deleted file mode 100644 index da7b437084..0000000000 --- a/vue-highlight/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-highlight", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-highlight/src/App.vue b/vue-highlight/src/App.vue deleted file mode 100644 index 1bea698fd7..0000000000 --- a/vue-highlight/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-highlight/src/app.css b/vue-highlight/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-highlight/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-highlight/src/components/editor/examples/highlight/editor.vue b/vue-highlight/src/components/editor/examples/highlight/editor.vue deleted file mode 100644 index 930156a17a..0000000000 --- a/vue-highlight/src/components/editor/examples/highlight/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-highlight/src/components/editor/examples/highlight/extension.ts b/vue-highlight/src/components/editor/examples/highlight/extension.ts deleted file mode 100644 index abc131c3be..0000000000 --- a/vue-highlight/src/components/editor/examples/highlight/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHighlight } from 'prosekit/extensions/highlight' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHighlight(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-highlight/src/components/editor/examples/highlight/index.ts b/vue-highlight/src/components/editor/examples/highlight/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-highlight/src/components/editor/examples/highlight/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-highlight/src/components/editor/examples/highlight/toolbar.vue b/vue-highlight/src/components/editor/examples/highlight/toolbar.vue deleted file mode 100644 index 2e6d3c1310..0000000000 --- a/vue-highlight/src/components/editor/examples/highlight/toolbar.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/vue-highlight/src/components/editor/sample/sample-doc-highlight.ts b/vue-highlight/src/components/editor/sample/sample-doc-highlight.ts deleted file mode 100644 index 0de1a1f7b2..0000000000 --- a/vue-highlight/src/components/editor/sample/sample-doc-highlight.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'highlight', - }, - ], - text: 'This is highlighted text', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/vue-highlight/src/components/editor/ui/button/button.vue b/vue-highlight/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-highlight/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-highlight/src/components/editor/ui/button/index.ts b/vue-highlight/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-highlight/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-highlight/src/main.ts b/vue-highlight/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-highlight/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-highlight/tsconfig.app.json b/vue-highlight/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-highlight/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-highlight/tsconfig.json b/vue-highlight/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-highlight/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-highlight/tsconfig.node.json b/vue-highlight/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-highlight/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-highlight/vite.config.ts b/vue-highlight/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-highlight/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-horizontal-rule/.gitignore b/vue-horizontal-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-horizontal-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-horizontal-rule/README.md b/vue-horizontal-rule/README.md deleted file mode 100644 index 074eb081e9..0000000000 --- a/vue-horizontal-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-horizontal-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-horizontal-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-horizontal-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-horizontal-rule vue-horizontal-rule -cd vue-horizontal-rule -npm install -npm run dev -``` diff --git a/vue-horizontal-rule/index.html b/vue-horizontal-rule/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-horizontal-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-horizontal-rule/package.json b/vue-horizontal-rule/package.json deleted file mode 100644 index adb7312241..0000000000 --- a/vue-horizontal-rule/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-horizontal-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-horizontal-rule/src/App.vue b/vue-horizontal-rule/src/App.vue deleted file mode 100644 index 805a365902..0000000000 --- a/vue-horizontal-rule/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-horizontal-rule/src/app.css b/vue-horizontal-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-horizontal-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.vue b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.vue deleted file mode 100644 index 7d4edcece6..0000000000 --- a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts deleted file mode 100644 index 49b6121eeb..0000000000 --- a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineHorizontalRule(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-horizontal-rule/src/components/editor/ui/button/button.vue b/vue-horizontal-rule/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-horizontal-rule/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-horizontal-rule/src/components/editor/ui/button/index.ts b/vue-horizontal-rule/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-horizontal-rule/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/vue-horizontal-rule/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-horizontal-rule/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-horizontal-rule/src/components/editor/ui/toolbar/toolbar.vue b/vue-horizontal-rule/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-horizontal-rule/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-horizontal-rule/src/main.ts b/vue-horizontal-rule/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-horizontal-rule/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-horizontal-rule/tsconfig.app.json b/vue-horizontal-rule/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-horizontal-rule/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-horizontal-rule/tsconfig.json b/vue-horizontal-rule/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-horizontal-rule/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-horizontal-rule/tsconfig.node.json b/vue-horizontal-rule/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-horizontal-rule/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-horizontal-rule/vite.config.ts b/vue-horizontal-rule/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-horizontal-rule/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-image-view/.gitignore b/vue-image-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-image-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-image-view/README.md b/vue-image-view/README.md deleted file mode 100644 index d0391ce760..0000000000 --- a/vue-image-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-image-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-image-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-image-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-image-view vue-image-view -cd vue-image-view -npm install -npm run dev -``` diff --git a/vue-image-view/index.html b/vue-image-view/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-image-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-image-view/package.json b/vue-image-view/package.json deleted file mode 100644 index eceb69d805..0000000000 --- a/vue-image-view/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-image-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-image-view/src/App.vue b/vue-image-view/src/App.vue deleted file mode 100644 index 047bb363a5..0000000000 --- a/vue-image-view/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-image-view/src/app.css b/vue-image-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-image-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-image-view/src/components/editor/examples/image-view/editor.vue b/vue-image-view/src/components/editor/examples/image-view/editor.vue deleted file mode 100644 index 63efeae16e..0000000000 --- a/vue-image-view/src/components/editor/examples/image-view/editor.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/vue-image-view/src/components/editor/examples/image-view/extension.ts b/vue-image-view/src/components/editor/examples/image-view/extension.ts deleted file mode 100644 index a21febf634..0000000000 --- a/vue-image-view/src/components/editor/examples/image-view/extension.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineImageUploadHandler } from 'prosekit/extensions/image' - -import { sampleUploader } from '../../sample/sample-uploader' -import { defineImageView } from '../../ui/image-view' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineImageView(), - defineImageUploadHandler({ - uploader: sampleUploader, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-image-view/src/components/editor/examples/image-view/index.ts b/vue-image-view/src/components/editor/examples/image-view/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-image-view/src/components/editor/examples/image-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-image-view/src/components/editor/sample/sample-doc-image.ts b/vue-image-view/src/components/editor/sample/sample-doc-image.ts deleted file mode 100644 index c97628339d..0000000000 --- a/vue-image-view/src/components/editor/sample/sample-doc-image.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Paste or drop an image to upload it.', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/white/200x200/1', - width: 160, - height: 160, - }, - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/yellow/640x360/42', - width: 240, - height: 135, - }, - }, - ], -} diff --git a/vue-image-view/src/components/editor/sample/sample-uploader.ts b/vue-image-view/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/vue-image-view/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/vue-image-view/src/components/editor/ui/image-view/image-view.vue b/vue-image-view/src/components/editor/ui/image-view/image-view.vue deleted file mode 100644 index a8beb8acd2..0000000000 --- a/vue-image-view/src/components/editor/ui/image-view/image-view.vue +++ /dev/null @@ -1,97 +0,0 @@ - - - diff --git a/vue-image-view/src/components/editor/ui/image-view/index.ts b/vue-image-view/src/components/editor/ui/image-view/index.ts deleted file mode 100644 index 960e2c64d6..0000000000 --- a/vue-image-view/src/components/editor/ui/image-view/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Extension } from 'prosekit/core' -import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' - -import ImageView from './image-view.vue' - -export function defineImageView(): Extension { - return defineVueNodeView({ - name: 'image', - component: ImageView as VueNodeViewComponent, - }) -} diff --git a/vue-image-view/src/main.ts b/vue-image-view/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-image-view/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-image-view/tsconfig.app.json b/vue-image-view/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-image-view/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-image-view/tsconfig.json b/vue-image-view/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-image-view/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-image-view/tsconfig.node.json b/vue-image-view/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-image-view/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-image-view/vite.config.ts b/vue-image-view/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-image-view/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-inline-menu/.gitignore b/vue-inline-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-inline-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-inline-menu/README.md b/vue-inline-menu/README.md deleted file mode 100644 index 13e5ba1650..0000000000 --- a/vue-inline-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-inline-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-inline-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-inline-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-inline-menu vue-inline-menu -cd vue-inline-menu -npm install -npm run dev -``` diff --git a/vue-inline-menu/index.html b/vue-inline-menu/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-inline-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-inline-menu/package.json b/vue-inline-menu/package.json deleted file mode 100644 index 0b1c24511a..0000000000 --- a/vue-inline-menu/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-inline-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-inline-menu/src/App.vue b/vue-inline-menu/src/App.vue deleted file mode 100644 index 4bc7cabf04..0000000000 --- a/vue-inline-menu/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-inline-menu/src/app.css b/vue-inline-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-inline-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-inline-menu/src/components/editor/examples/inline-menu/editor.vue b/vue-inline-menu/src/components/editor/examples/inline-menu/editor.vue deleted file mode 100644 index 35a0904198..0000000000 --- a/vue-inline-menu/src/components/editor/examples/inline-menu/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/vue-inline-menu/src/components/editor/examples/inline-menu/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/vue-inline-menu/src/components/editor/examples/inline-menu/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/vue-inline-menu/src/components/editor/examples/inline-menu/index.ts b/vue-inline-menu/src/components/editor/examples/inline-menu/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-inline-menu/src/components/editor/examples/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/vue-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts deleted file mode 100644 index 62a5984cb0..0000000000 --- a/vue-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const loremText = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'Try to select some text', - }, - ], - }, - ...Array.from({ length: 10 }, () => ({ - type: 'paragraph' as const, - content: [ - { - type: 'text' as const, - text: loremText, - }, - ], - })), - ], -} diff --git a/vue-inline-menu/src/components/editor/ui/button/button.vue b/vue-inline-menu/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-inline-menu/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-inline-menu/src/components/editor/ui/button/index.ts b/vue-inline-menu/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-inline-menu/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-inline-menu/src/components/editor/ui/inline-menu/index.ts b/vue-inline-menu/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8c72e460c8..0000000000 --- a/vue-inline-menu/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-inline-menu/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-inline-menu/src/components/editor/ui/inline-menu/inline-menu.vue deleted file mode 100644 index cacb76b189..0000000000 --- a/vue-inline-menu/src/components/editor/ui/inline-menu/inline-menu.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - diff --git a/vue-inline-menu/src/main.ts b/vue-inline-menu/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-inline-menu/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-inline-menu/tsconfig.app.json b/vue-inline-menu/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-inline-menu/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-inline-menu/tsconfig.json b/vue-inline-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-inline-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-inline-menu/tsconfig.node.json b/vue-inline-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-inline-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-inline-menu/vite.config.ts b/vue-inline-menu/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-inline-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-italic/.gitignore b/vue-italic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-italic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-italic/README.md b/vue-italic/README.md deleted file mode 100644 index 755e74cbbc..0000000000 --- a/vue-italic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-italic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-italic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-italic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-italic vue-italic -cd vue-italic -npm install -npm run dev -``` diff --git a/vue-italic/index.html b/vue-italic/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-italic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-italic/package.json b/vue-italic/package.json deleted file mode 100644 index a6aaca4808..0000000000 --- a/vue-italic/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-italic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-italic/src/App.vue b/vue-italic/src/App.vue deleted file mode 100644 index 398832bc53..0000000000 --- a/vue-italic/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-italic/src/app.css b/vue-italic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-italic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-italic/src/components/editor/examples/italic/editor.vue b/vue-italic/src/components/editor/examples/italic/editor.vue deleted file mode 100644 index db1429707f..0000000000 --- a/vue-italic/src/components/editor/examples/italic/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-italic/src/components/editor/examples/italic/extension.ts b/vue-italic/src/components/editor/examples/italic/extension.ts deleted file mode 100644 index a456b06aad..0000000000 --- a/vue-italic/src/components/editor/examples/italic/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineItalic(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-italic/src/components/editor/examples/italic/index.ts b/vue-italic/src/components/editor/examples/italic/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-italic/src/components/editor/examples/italic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-italic/src/components/editor/sample/sample-doc-italic.ts b/vue-italic/src/components/editor/sample/sample-doc-italic.ts deleted file mode 100644 index fb99415b2c..0000000000 --- a/vue-italic/src/components/editor/sample/sample-doc-italic.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'This is italic too', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/vue-italic/src/components/editor/ui/button/button.vue b/vue-italic/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-italic/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-italic/src/components/editor/ui/button/index.ts b/vue-italic/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-italic/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-italic/src/components/editor/ui/image-upload-popover/index.ts b/vue-italic/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-italic/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-italic/src/components/editor/ui/toolbar/index.ts b/vue-italic/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-italic/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-italic/src/components/editor/ui/toolbar/toolbar.vue b/vue-italic/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-italic/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-italic/src/main.ts b/vue-italic/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-italic/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-italic/tsconfig.app.json b/vue-italic/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-italic/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-italic/tsconfig.json b/vue-italic/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-italic/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-italic/tsconfig.node.json b/vue-italic/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-italic/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-italic/vite.config.ts b/vue-italic/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-italic/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-katex/.gitignore b/vue-katex/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-katex/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-katex/README.md b/vue-katex/README.md deleted file mode 100644 index b995c8e803..0000000000 --- a/vue-katex/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-katex - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-katex) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-katex) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-katex vue-katex -cd vue-katex -npm install -npm run dev -``` diff --git a/vue-katex/index.html b/vue-katex/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-katex/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-katex/package.json b/vue-katex/package.json deleted file mode 100644 index 1c59359c61..0000000000 --- a/vue-katex/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-vue-katex", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-katex/src/App.vue b/vue-katex/src/App.vue deleted file mode 100644 index 8d28f5c33a..0000000000 --- a/vue-katex/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-katex/src/app.css b/vue-katex/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-katex/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-katex/src/components/editor/examples/katex/editor.vue b/vue-katex/src/components/editor/examples/katex/editor.vue deleted file mode 100644 index 7a5c4d69a9..0000000000 --- a/vue-katex/src/components/editor/examples/katex/editor.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/vue-katex/src/components/editor/examples/katex/extension.ts b/vue-katex/src/components/editor/examples/katex/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/vue-katex/src/components/editor/examples/katex/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-katex/src/components/editor/examples/katex/index.ts b/vue-katex/src/components/editor/examples/katex/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-katex/src/components/editor/examples/katex/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-katex/src/components/editor/sample/katex.ts b/vue-katex/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/vue-katex/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/vue-katex/src/components/editor/sample/sample-doc-tex.ts b/vue-katex/src/components/editor/sample/sample-doc-tex.ts deleted file mode 100644 index 21ccf3e94e..0000000000 --- a/vue-katex/src/components/editor/sample/sample-doc-tex.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Inline equations' }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text. Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, - { type: 'text', text: ' to insert an inline equation.' }, - ], - }, - { - type: 'heading', - attrs: { level: 2 }, - content: [{ type: 'text', text: 'Block equations' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: 'The Gaussian integral:' }], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: 'Type ' }, - { type: 'text', marks: [{ type: 'code' }], text: '$$' }, - { - type: 'text', - text: ' in a new line and press Enter to create a block equation.', - }, - ], - }, - ], -} diff --git a/vue-katex/src/main.ts b/vue-katex/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-katex/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-katex/tsconfig.app.json b/vue-katex/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-katex/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-katex/tsconfig.json b/vue-katex/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-katex/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-katex/tsconfig.node.json b/vue-katex/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-katex/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-katex/vite.config.ts b/vue-katex/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-katex/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-keymap/.gitignore b/vue-keymap/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-keymap/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-keymap/README.md b/vue-keymap/README.md deleted file mode 100644 index 9d4d310193..0000000000 --- a/vue-keymap/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-keymap - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-keymap) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-keymap) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-keymap vue-keymap -cd vue-keymap -npm install -npm run dev -``` diff --git a/vue-keymap/index.html b/vue-keymap/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-keymap/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-keymap/package.json b/vue-keymap/package.json deleted file mode 100644 index 96128af33c..0000000000 --- a/vue-keymap/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-keymap", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-keymap/src/App.vue b/vue-keymap/src/App.vue deleted file mode 100644 index bf4823a430..0000000000 --- a/vue-keymap/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-keymap/src/app.css b/vue-keymap/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-keymap/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-keymap/src/components/editor/examples/keymap/editor.vue b/vue-keymap/src/components/editor/examples/keymap/editor.vue deleted file mode 100644 index 2854f9624a..0000000000 --- a/vue-keymap/src/components/editor/examples/keymap/editor.vue +++ /dev/null @@ -1,49 +0,0 @@ - - - diff --git a/vue-keymap/src/components/editor/examples/keymap/extension.ts b/vue-keymap/src/components/editor/examples/keymap/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/vue-keymap/src/components/editor/examples/keymap/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/vue-keymap/src/components/editor/examples/keymap/index.ts b/vue-keymap/src/components/editor/examples/keymap/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-keymap/src/components/editor/examples/keymap/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-keymap/src/components/editor/examples/keymap/toolbar.vue b/vue-keymap/src/components/editor/examples/keymap/toolbar.vue deleted file mode 100644 index a84456c1f3..0000000000 --- a/vue-keymap/src/components/editor/examples/keymap/toolbar.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - diff --git a/vue-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts b/vue-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts deleted file mode 100644 index 8aa8777560..0000000000 --- a/vue-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Keymap } from 'prosekit/core' -import { useKeymap } from 'prosekit/vue' -import { computed, type Ref } from 'vue' - -export function useSubmitKeymap( - hotkey: Ref<'Shift-Enter' | 'Enter'>, - onSubmit: (hotkey: string) => void, -) { - const keymap = computed(() => { - return { - [hotkey.value]: () => { - onSubmit(hotkey.value) - return true - }, - } - }) - - useKeymap(keymap) -} diff --git a/vue-keymap/src/components/editor/ui/button/button.vue b/vue-keymap/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-keymap/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-keymap/src/components/editor/ui/button/index.ts b/vue-keymap/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-keymap/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-keymap/src/main.ts b/vue-keymap/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-keymap/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-keymap/tsconfig.app.json b/vue-keymap/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-keymap/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-keymap/tsconfig.json b/vue-keymap/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-keymap/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-keymap/tsconfig.node.json b/vue-keymap/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-keymap/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-keymap/vite.config.ts b/vue-keymap/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-keymap/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-link-mark-view/.gitignore b/vue-link-mark-view/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-link-mark-view/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-link-mark-view/README.md b/vue-link-mark-view/README.md deleted file mode 100644 index a3fc62d78b..0000000000 --- a/vue-link-mark-view/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-link-mark-view - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-link-mark-view) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-link-mark-view) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-link-mark-view vue-link-mark-view -cd vue-link-mark-view -npm install -npm run dev -``` diff --git a/vue-link-mark-view/index.html b/vue-link-mark-view/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-link-mark-view/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-link-mark-view/package.json b/vue-link-mark-view/package.json deleted file mode 100644 index ac288d419e..0000000000 --- a/vue-link-mark-view/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-link-mark-view", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-link-mark-view/src/App.vue b/vue-link-mark-view/src/App.vue deleted file mode 100644 index 35cafd2c7b..0000000000 --- a/vue-link-mark-view/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-link-mark-view/src/app.css b/vue-link-mark-view/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-link-mark-view/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-link-mark-view/src/components/editor/examples/link-mark-view/editor.vue b/vue-link-mark-view/src/components/editor/examples/link-mark-view/editor.vue deleted file mode 100644 index c90a5b537d..0000000000 --- a/vue-link-mark-view/src/components/editor/examples/link-mark-view/editor.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/vue-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/vue-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts deleted file mode 100644 index 5e85a8f55b..0000000000 --- a/vue-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineVueMarkView, type VueMarkViewComponent } from 'prosekit/vue' - -import LinkView from './link-view.vue' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineVueMarkView({ - name: 'link', - component: LinkView as VueMarkViewComponent, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/vue-link-mark-view/src/components/editor/examples/link-mark-view/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-link-mark-view/src/components/editor/examples/link-mark-view/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-link-mark-view/src/components/editor/examples/link-mark-view/link-view.vue b/vue-link-mark-view/src/components/editor/examples/link-mark-view/link-view.vue deleted file mode 100644 index 4353904d26..0000000000 --- a/vue-link-mark-view/src/components/editor/examples/link-mark-view/link-view.vue +++ /dev/null @@ -1,48 +0,0 @@ - - - diff --git a/vue-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/vue-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts deleted file mode 100644 index 57abd09dd6..0000000000 --- a/vue-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is a link that changes color every second: ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/vue-link-mark-view/src/main.ts b/vue-link-mark-view/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-link-mark-view/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-link-mark-view/tsconfig.app.json b/vue-link-mark-view/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-link-mark-view/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-link-mark-view/tsconfig.json b/vue-link-mark-view/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-link-mark-view/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-link-mark-view/tsconfig.node.json b/vue-link-mark-view/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-link-mark-view/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-link-mark-view/vite.config.ts b/vue-link-mark-view/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-link-mark-view/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-link/.gitignore b/vue-link/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-link/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-link/README.md b/vue-link/README.md deleted file mode 100644 index dff3467791..0000000000 --- a/vue-link/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-link - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-link) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-link) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-link vue-link -cd vue-link -npm install -npm run dev -``` diff --git a/vue-link/index.html b/vue-link/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-link/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-link/package.json b/vue-link/package.json deleted file mode 100644 index 413e1629e3..0000000000 --- a/vue-link/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-link", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-link/src/App.vue b/vue-link/src/App.vue deleted file mode 100644 index 5fb5eba0eb..0000000000 --- a/vue-link/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-link/src/app.css b/vue-link/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-link/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-link/src/components/editor/examples/link/editor.vue b/vue-link/src/components/editor/examples/link/editor.vue deleted file mode 100644 index 51213a7af0..0000000000 --- a/vue-link/src/components/editor/examples/link/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-link/src/components/editor/examples/link/extension.ts b/vue-link/src/components/editor/examples/link/extension.ts deleted file mode 100644 index bf499147da..0000000000 --- a/vue-link/src/components/editor/examples/link/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLink } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-link/src/components/editor/examples/link/index.ts b/vue-link/src/components/editor/examples/link/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-link/src/components/editor/examples/link/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-link/src/components/editor/sample/sample-doc-link.ts b/vue-link/src/components/editor/sample/sample-doc-link.ts deleted file mode 100644 index 726cf334fd..0000000000 --- a/vue-link/src/components/editor/sample/sample-doc-link.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here is an ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://www.example.com', - target: null, - rel: null, - }, - }, - ], - text: 'example link', - }, - ], - }, - ], -} diff --git a/vue-link/src/components/editor/ui/button/button.vue b/vue-link/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-link/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-link/src/components/editor/ui/button/index.ts b/vue-link/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-link/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-link/src/components/editor/ui/inline-menu/index.ts b/vue-link/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8c72e460c8..0000000000 --- a/vue-link/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-link/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-link/src/components/editor/ui/inline-menu/inline-menu.vue deleted file mode 100644 index cacb76b189..0000000000 --- a/vue-link/src/components/editor/ui/inline-menu/inline-menu.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - diff --git a/vue-link/src/main.ts b/vue-link/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-link/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-link/tsconfig.app.json b/vue-link/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-link/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-link/tsconfig.json b/vue-link/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-link/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-link/tsconfig.node.json b/vue-link/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-link/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-link/vite.config.ts b/vue-link/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-link/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-list-custom-checkbox/.gitignore b/vue-list-custom-checkbox/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-list-custom-checkbox/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-list-custom-checkbox/README.md b/vue-list-custom-checkbox/README.md deleted file mode 100644 index 2eba5804ac..0000000000 --- a/vue-list-custom-checkbox/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-list-custom-checkbox - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-list-custom-checkbox) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-list-custom-checkbox) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-list-custom-checkbox vue-list-custom-checkbox -cd vue-list-custom-checkbox -npm install -npm run dev -``` diff --git a/vue-list-custom-checkbox/index.html b/vue-list-custom-checkbox/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-list-custom-checkbox/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-list-custom-checkbox/package.json b/vue-list-custom-checkbox/package.json deleted file mode 100644 index 969ffe88d8..0000000000 --- a/vue-list-custom-checkbox/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-list-custom-checkbox", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-list-custom-checkbox/src/App.vue b/vue-list-custom-checkbox/src/App.vue deleted file mode 100644 index af9081cb9e..0000000000 --- a/vue-list-custom-checkbox/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-list-custom-checkbox/src/app.css b/vue-list-custom-checkbox/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-list-custom-checkbox/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css deleted file mode 100644 index ec631b72ad..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css +++ /dev/null @@ -1,75 +0,0 @@ -div[data-custom-list-css-enabled] - .ProseMirror - .prosemirror-flat-list[data-list-kind='task'] { - & > .list-marker label { - box-sizing: border-box; - display: flex; - position: relative; - left: calc(var(--spacing) * -0.5); - align-items: center; - cursor: pointer; - transition: transform 0.15s ease-in-out; - - &:hover { - transform: scale(1.1); - } - - &::after { - position: absolute; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - content: ''; - color: var(--color-white); - opacity: 0; - } - - /* https://api.iconify.design/lucide.css?icons=check */ - &::after { - display: inline-block; - background-color: currentColor; - -webkit-mask-image: var(--svg); - mask-image: var(--svg); - -webkit-mask-repeat: no-repeat; - mask-repeat: no-repeat; - -webkit-mask-size: 100% 100%; - mask-size: 100% 100%; - --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); - } - - & input { - box-sizing: border-box; - appearance: none; - width: calc(var(--spacing) * 5); - height: calc(var(--spacing) * 5); - margin: 0; - border-width: 1px; - border-style: solid; - border-radius: var(--radius-md); - border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); - box-shadow: var(--shadow-sm); - cursor: pointer; - transition: all 0.15s ease-in-out; - - &:hover { - box-shadow: var(--shadow-md); - } - - &:checked { - border-color: var(--color-red-500); - background-color: var(--color-red-500); - } - } - } - - &[data-list-checked] > .list-marker label { - &::after { - opacity: 1; - } - } - - &[data-list-checked] { - color: var(--color-gray-400); - text-decoration: line-through; - text-decoration-color: var(--color-gray-400); - } -} diff --git a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.vue b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.vue deleted file mode 100644 index 0dc311c847..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/vue-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts deleted file mode 100644 index 972611aed1..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', - }, - { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, - { type: 'text', text: ' for the styles.' }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Completed Task' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Incomplete Task' }], - }, - ], - }, - ], -} diff --git a/vue-list-custom-checkbox/src/components/editor/ui/button/button.vue b/vue-list-custom-checkbox/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-list-custom-checkbox/src/components/editor/ui/button/index.ts b/vue-list-custom-checkbox/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/vue-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.vue b/vue-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-list-custom-checkbox/src/main.ts b/vue-list-custom-checkbox/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-list-custom-checkbox/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-list-custom-checkbox/tsconfig.app.json b/vue-list-custom-checkbox/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-list-custom-checkbox/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-list-custom-checkbox/tsconfig.json b/vue-list-custom-checkbox/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-list-custom-checkbox/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-list-custom-checkbox/tsconfig.node.json b/vue-list-custom-checkbox/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-list-custom-checkbox/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-list-custom-checkbox/vite.config.ts b/vue-list-custom-checkbox/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-list-custom-checkbox/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-list/.gitignore b/vue-list/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-list/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-list/README.md b/vue-list/README.md deleted file mode 100644 index ceeabfefab..0000000000 --- a/vue-list/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-list - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-list) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-list) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-list vue-list -cd vue-list -npm install -npm run dev -``` diff --git a/vue-list/index.html b/vue-list/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-list/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-list/package.json b/vue-list/package.json deleted file mode 100644 index 2fb8f9cc6b..0000000000 --- a/vue-list/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-list", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-list/src/App.vue b/vue-list/src/App.vue deleted file mode 100644 index 01a39b3560..0000000000 --- a/vue-list/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-list/src/app.css b/vue-list/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-list/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-list/src/components/editor/examples/list/editor.vue b/vue-list/src/components/editor/examples/list/editor.vue deleted file mode 100644 index 02d30c8015..0000000000 --- a/vue-list/src/components/editor/examples/list/editor.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/vue-list/src/components/editor/examples/list/extension.ts b/vue-list/src/components/editor/examples/list/extension.ts deleted file mode 100644 index f66bae6ff7..0000000000 --- a/vue-list/src/components/editor/examples/list/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineList } from 'prosekit/extensions/list' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineList(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-list/src/components/editor/examples/list/index.ts b/vue-list/src/components/editor/examples/list/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-list/src/components/editor/examples/list/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-list/src/components/editor/sample/sample-doc-list.ts b/vue-list/src/components/editor/sample/sample-doc-list.ts deleted file mode 100644 index 091bc37185..0000000000 --- a/vue-list/src/components/editor/sample/sample-doc-list.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: 'Ordered List' }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, - ], - }, - { - type: 'list', - attrs: { kind: 'toggle', collapsed: true }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, - { - type: 'list', - attrs: { - kind: 'bullet', - }, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, - ], - }, - ], - }, - ], -} diff --git a/vue-list/src/components/editor/ui/button/button.vue b/vue-list/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-list/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-list/src/components/editor/ui/button/index.ts b/vue-list/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-list/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-list/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-list/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-list/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-list/src/components/editor/ui/image-upload-popover/index.ts b/vue-list/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-list/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-list/src/components/editor/ui/toolbar/index.ts b/vue-list/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-list/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-list/src/components/editor/ui/toolbar/toolbar.vue b/vue-list/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-list/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-list/src/main.ts b/vue-list/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-list/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-list/tsconfig.app.json b/vue-list/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-list/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-list/tsconfig.json b/vue-list/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-list/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-list/tsconfig.node.json b/vue-list/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-list/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-list/vite.config.ts b/vue-list/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-list/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-loro/.gitignore b/vue-loro/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-loro/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-loro/README.md b/vue-loro/README.md deleted file mode 100644 index 68c1425266..0000000000 --- a/vue-loro/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-loro - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-loro) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-loro) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-loro vue-loro -cd vue-loro -npm install -npm run dev -``` diff --git a/vue-loro/index.html b/vue-loro/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-loro/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-loro/package.json b/vue-loro/package.json deleted file mode 100644 index c4a1832c8c..0000000000 --- a/vue-loro/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "example-vue-loro", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "loro-crdt": "^1.12.1", - "loro-prosemirror": "^0.4.3", - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vite-plugin-wasm": "^3.6.0", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-loro/src/App.vue b/vue-loro/src/App.vue deleted file mode 100644 index 17defcfc3e..0000000000 --- a/vue-loro/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-loro/src/app.css b/vue-loro/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-loro/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-loro/src/components/editor/examples/loro/editor-component.vue b/vue-loro/src/components/editor/examples/loro/editor-component.vue deleted file mode 100644 index 906dbff4cb..0000000000 --- a/vue-loro/src/components/editor/examples/loro/editor-component.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/vue-loro/src/components/editor/examples/loro/editor.vue b/vue-loro/src/components/editor/examples/loro/editor.vue deleted file mode 100644 index 1699f8ae88..0000000000 --- a/vue-loro/src/components/editor/examples/loro/editor.vue +++ /dev/null @@ -1,56 +0,0 @@ - - - diff --git a/vue-loro/src/components/editor/examples/loro/extension.ts b/vue-loro/src/components/editor/examples/loro/extension.ts deleted file mode 100644 index 5a85c5e168..0000000000 --- a/vue-loro/src/components/editor/examples/loro/extension.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineLoro } from 'prosekit/extensions/loro' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { - return union([ - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineLoro({ doc, awareness }), - ]) -} - -export type EditorExtension = ReturnType diff --git a/vue-loro/src/components/editor/examples/loro/index.ts b/vue-loro/src/components/editor/examples/loro/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-loro/src/components/editor/examples/loro/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-loro/src/components/editor/ui/button/button.vue b/vue-loro/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-loro/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-loro/src/components/editor/ui/button/index.ts b/vue-loro/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-loro/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-loro/src/components/editor/ui/image-upload-popover/index.ts b/vue-loro/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-loro/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-loro/src/components/editor/ui/toolbar/index.ts b/vue-loro/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-loro/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-loro/src/components/editor/ui/toolbar/toolbar.vue b/vue-loro/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-loro/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-loro/src/main.ts b/vue-loro/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-loro/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-loro/tsconfig.app.json b/vue-loro/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-loro/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-loro/tsconfig.json b/vue-loro/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-loro/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-loro/tsconfig.node.json b/vue-loro/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-loro/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-loro/vite.config.ts b/vue-loro/vite.config.ts deleted file mode 100644 index ffb2555728..0000000000 --- a/vue-loro/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import wasm from 'vite-plugin-wasm' -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [wasm(), vue(), tailwindcss()], -}) diff --git a/vue-mark-rule/.gitignore b/vue-mark-rule/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-mark-rule/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-mark-rule/README.md b/vue-mark-rule/README.md deleted file mode 100644 index 5973b90538..0000000000 --- a/vue-mark-rule/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-mark-rule - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-mark-rule) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-mark-rule) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-mark-rule vue-mark-rule -cd vue-mark-rule -npm install -npm run dev -``` diff --git a/vue-mark-rule/index.html b/vue-mark-rule/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-mark-rule/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-mark-rule/package.json b/vue-mark-rule/package.json deleted file mode 100644 index ec030ddc3e..0000000000 --- a/vue-mark-rule/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-mark-rule", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-mark-rule/src/App.vue b/vue-mark-rule/src/App.vue deleted file mode 100644 index 2446156889..0000000000 --- a/vue-mark-rule/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-mark-rule/src/app.css b/vue-mark-rule/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-mark-rule/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-mark-rule/src/components/editor/examples/mark-rule/editor.vue b/vue-mark-rule/src/components/editor/examples/mark-rule/editor.vue deleted file mode 100644 index d8707ded7c..0000000000 --- a/vue-mark-rule/src/components/editor/examples/mark-rule/editor.vue +++ /dev/null @@ -1,27 +0,0 @@ - - - diff --git a/vue-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/vue-mark-rule/src/components/editor/examples/mark-rule/extension.ts deleted file mode 100644 index 4a1de40783..0000000000 --- a/vue-mark-rule/src/components/editor/examples/mark-rule/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - defineBaseCommands, - defineBaseKeymap, - defineHistory, - union, -} from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { definePlaceholder } from 'prosekit/extensions/placeholder' -import { defineText } from 'prosekit/extensions/text' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' - -import { defineIssueLink } from './issue-link' - -export function defineExtension() { - return union( - defineDoc(), - defineText(), - defineParagraph(), - defineHistory(), - defineBaseKeymap(), - defineBaseCommands(), - defineVirtualSelection(), - defineLinkSpec(), - defineLinkMarkRule(), - definePlaceholder({ placeholder: 'Try typing #123' }), - defineIssueLink(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-mark-rule/src/components/editor/examples/mark-rule/index.ts b/vue-mark-rule/src/components/editor/examples/mark-rule/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-mark-rule/src/components/editor/examples/mark-rule/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/vue-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts deleted file mode 100644 index 3840b5e53d..0000000000 --- a/vue-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { defineMarkSpec, union } from 'prosekit/core' -import { defineMarkRule } from 'prosekit/extensions/mark-rule' - -export function defineIssueLink() { - return union( - defineMarkSpec({ - name: 'issueLink', - inclusive: false, - attrs: { - issueNumber: {}, - }, - toDOM(node) { - const issueNumber = node.attrs.issueNumber as number - return [ - 'a', - { - href: `https://example.com/issues/${issueNumber}`, - title: `Issue #${issueNumber}`, - }, - 0, - ] - }, - }), - defineMarkRule({ - regex: /#(\d+)/g, - type: 'issueLink', - attrs: (match) => { - return { issueNumber: Number.parseInt(match[1] || '0') } - }, - }), - ) -} diff --git a/vue-mark-rule/src/main.ts b/vue-mark-rule/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-mark-rule/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-mark-rule/tsconfig.app.json b/vue-mark-rule/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-mark-rule/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-mark-rule/tsconfig.json b/vue-mark-rule/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-mark-rule/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-mark-rule/tsconfig.node.json b/vue-mark-rule/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-mark-rule/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-mark-rule/vite.config.ts b/vue-mark-rule/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-mark-rule/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-minimal/.gitignore b/vue-minimal/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-minimal/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-minimal/README.md b/vue-minimal/README.md deleted file mode 100644 index 0a552ae9b9..0000000000 --- a/vue-minimal/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-minimal - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-minimal) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-minimal) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-minimal vue-minimal -cd vue-minimal -npm install -npm run dev -``` diff --git a/vue-minimal/index.html b/vue-minimal/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-minimal/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-minimal/package.json b/vue-minimal/package.json deleted file mode 100644 index d909f51da6..0000000000 --- a/vue-minimal/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-minimal", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-minimal/src/App.vue b/vue-minimal/src/App.vue deleted file mode 100644 index 19ffd1d801..0000000000 --- a/vue-minimal/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-minimal/src/app.css b/vue-minimal/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-minimal/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-minimal/src/components/editor/examples/minimal/editor.vue b/vue-minimal/src/components/editor/examples/minimal/editor.vue deleted file mode 100644 index 145f522bd6..0000000000 --- a/vue-minimal/src/components/editor/examples/minimal/editor.vue +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/vue-minimal/src/components/editor/examples/minimal/index.ts b/vue-minimal/src/components/editor/examples/minimal/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-minimal/src/components/editor/examples/minimal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-minimal/src/main.ts b/vue-minimal/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-minimal/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-minimal/tsconfig.app.json b/vue-minimal/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-minimal/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-minimal/tsconfig.json b/vue-minimal/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-minimal/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-minimal/tsconfig.node.json b/vue-minimal/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-minimal/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-minimal/vite.config.ts b/vue-minimal/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-minimal/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-placeholder/.gitignore b/vue-placeholder/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-placeholder/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-placeholder/README.md b/vue-placeholder/README.md deleted file mode 100644 index 16b679f5e4..0000000000 --- a/vue-placeholder/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-placeholder - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-placeholder) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-placeholder) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-placeholder vue-placeholder -cd vue-placeholder -npm install -npm run dev -``` diff --git a/vue-placeholder/index.html b/vue-placeholder/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-placeholder/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-placeholder/package.json b/vue-placeholder/package.json deleted file mode 100644 index acbe27df66..0000000000 --- a/vue-placeholder/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-placeholder", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-placeholder/src/App.vue b/vue-placeholder/src/App.vue deleted file mode 100644 index 82d3e6c263..0000000000 --- a/vue-placeholder/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-placeholder/src/app.css b/vue-placeholder/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-placeholder/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-placeholder/src/components/editor/examples/placeholder/editor.vue b/vue-placeholder/src/components/editor/examples/placeholder/editor.vue deleted file mode 100644 index dd57454b64..0000000000 --- a/vue-placeholder/src/components/editor/examples/placeholder/editor.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/vue-placeholder/src/components/editor/examples/placeholder/extension.ts b/vue-placeholder/src/components/editor/examples/placeholder/extension.ts deleted file mode 100644 index 12d0ba26f4..0000000000 --- a/vue-placeholder/src/components/editor/examples/placeholder/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Type something...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-placeholder/src/components/editor/examples/placeholder/index.ts b/vue-placeholder/src/components/editor/examples/placeholder/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-placeholder/src/components/editor/examples/placeholder/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-placeholder/src/main.ts b/vue-placeholder/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-placeholder/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-placeholder/tsconfig.app.json b/vue-placeholder/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-placeholder/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-placeholder/tsconfig.json b/vue-placeholder/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-placeholder/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-placeholder/tsconfig.node.json b/vue-placeholder/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-placeholder/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-placeholder/vite.config.ts b/vue-placeholder/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-placeholder/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-readonly/.gitignore b/vue-readonly/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-readonly/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-readonly/README.md b/vue-readonly/README.md deleted file mode 100644 index ae78f92eb8..0000000000 --- a/vue-readonly/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-readonly - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-readonly) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-readonly) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-readonly vue-readonly -cd vue-readonly -npm install -npm run dev -``` diff --git a/vue-readonly/index.html b/vue-readonly/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-readonly/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-readonly/package.json b/vue-readonly/package.json deleted file mode 100644 index 156aa3eabb..0000000000 --- a/vue-readonly/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-readonly", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-readonly/src/App.vue b/vue-readonly/src/App.vue deleted file mode 100644 index 2f82ce1dd8..0000000000 --- a/vue-readonly/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-readonly/src/app.css b/vue-readonly/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-readonly/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-readonly/src/components/editor/examples/readonly/editor.vue b/vue-readonly/src/components/editor/examples/readonly/editor.vue deleted file mode 100644 index 7fb2c31a5a..0000000000 --- a/vue-readonly/src/components/editor/examples/readonly/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-readonly/src/components/editor/examples/readonly/extension.ts b/vue-readonly/src/components/editor/examples/readonly/extension.ts deleted file mode 100644 index 15210b5dc0..0000000000 --- a/vue-readonly/src/components/editor/examples/readonly/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' - -export function defineExtension() { - return defineBasicExtension() -} - -export type EditorExtension = ReturnType diff --git a/vue-readonly/src/components/editor/examples/readonly/index.ts b/vue-readonly/src/components/editor/examples/readonly/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-readonly/src/components/editor/examples/readonly/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-readonly/src/components/editor/examples/readonly/toolbar.vue b/vue-readonly/src/components/editor/examples/readonly/toolbar.vue deleted file mode 100644 index e2100bbe5b..0000000000 --- a/vue-readonly/src/components/editor/examples/readonly/toolbar.vue +++ /dev/null @@ -1,17 +0,0 @@ - - - diff --git a/vue-readonly/src/components/editor/examples/readonly/use-readonly.ts b/vue-readonly/src/components/editor/examples/readonly/use-readonly.ts deleted file mode 100644 index db678caef3..0000000000 --- a/vue-readonly/src/components/editor/examples/readonly/use-readonly.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { defineReadonly } from 'prosekit/extensions/readonly' -import { useExtension } from 'prosekit/vue' -import { computed, ref } from 'vue' - -export function useReadonly() { - const readonly = ref(true) - - const extension = computed(() => { - return readonly.value ? defineReadonly() : null - }) - useExtension(extension) - - function setReadonly(value: boolean) { - readonly.value = value - } - - return { readonly, setReadonly } -} diff --git a/vue-readonly/src/components/editor/sample/sample-doc-readonly.ts b/vue-readonly/src/components/editor/sample/sample-doc-readonly.ts deleted file mode 100644 index abd9e2c6ac..0000000000 --- a/vue-readonly/src/components/editor/sample/sample-doc-readonly.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', - }, - ], - }, - ], -} diff --git a/vue-readonly/src/components/editor/ui/button/button.vue b/vue-readonly/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-readonly/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-readonly/src/components/editor/ui/button/index.ts b/vue-readonly/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-readonly/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-readonly/src/main.ts b/vue-readonly/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-readonly/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-readonly/tsconfig.app.json b/vue-readonly/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-readonly/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-readonly/tsconfig.json b/vue-readonly/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-readonly/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-readonly/tsconfig.node.json b/vue-readonly/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-readonly/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-readonly/vite.config.ts b/vue-readonly/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-readonly/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-rtl/.gitignore b/vue-rtl/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-rtl/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-rtl/README.md b/vue-rtl/README.md deleted file mode 100644 index 59f5f6f166..0000000000 --- a/vue-rtl/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-rtl - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-rtl) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-rtl) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-rtl vue-rtl -cd vue-rtl -npm install -npm run dev -``` diff --git a/vue-rtl/index.html b/vue-rtl/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-rtl/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-rtl/package.json b/vue-rtl/package.json deleted file mode 100644 index 1eb5863ec3..0000000000 --- a/vue-rtl/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-rtl", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-rtl/src/App.vue b/vue-rtl/src/App.vue deleted file mode 100644 index ced37540ee..0000000000 --- a/vue-rtl/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-rtl/src/app.css b/vue-rtl/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-rtl/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-rtl/src/components/editor/examples/rtl/editor.vue b/vue-rtl/src/components/editor/examples/rtl/editor.vue deleted file mode 100644 index 6161fc7ef8..0000000000 --- a/vue-rtl/src/components/editor/examples/rtl/editor.vue +++ /dev/null @@ -1,47 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/examples/rtl/index.ts b/vue-rtl/src/components/editor/examples/rtl/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-rtl/src/components/editor/examples/rtl/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-rtl/src/components/editor/sample/sample-doc-rtl.ts b/vue-rtl/src/components/editor/sample/sample-doc-rtl.ts deleted file mode 100644 index 696e797724..0000000000 --- a/vue-rtl/src/components/editor/sample/sample-doc-rtl.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const translation = { - Paragraph: 'فقرة', - 'Root list item': 'عنصر قائمة جذري', - 'Sub list item': 'عنصر قائمة فرعي', - 'Completed task': 'مهمة مكتملة', - 'Pending task': 'مهمة قيد الانتظار', - Quote: 'اقتباس', -} as const - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { level: 1 }, - content: [{ type: 'text', text: 'Right to Left' }], - }, - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Paragraph'] }], - }, - { - type: 'list', - attrs: { kind: 'bullet' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Root list item'] }], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'ordered' }, - content: [ - { - type: 'paragraph', - content: [{ type: 'text', text: translation['Sub list item'] }], - }, - { - type: 'list', - attrs: { kind: 'task', checked: true }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Completed task'] }, - ], - }, - ], - }, - { - type: 'list', - attrs: { kind: 'task', checked: false }, - content: [ - { - type: 'paragraph', - content: [ - { type: 'text', text: translation['Pending task'] }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'codeBlock', - attrs: { language: 'javascript' }, - content: [ - { - type: 'text', - text: 'hello world', - }, - ], - }, - - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, - ], - }, - { - type: 'tableCell', - attrs: {}, - content: [ - { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, - ], - }, - ], - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: translation['Quote'], - }, - ], - }, - ], - }, - ], -} diff --git a/vue-rtl/src/components/editor/sample/sample-uploader.ts b/vue-rtl/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/vue-rtl/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/vue-rtl/src/components/editor/ui/block-handle/block-handle.vue b/vue-rtl/src/components/editor/ui/block-handle/block-handle.vue deleted file mode 100644 index ba06a1416a..0000000000 --- a/vue-rtl/src/components/editor/ui/block-handle/block-handle.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/block-handle/index.ts b/vue-rtl/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 2c33eb5726..0000000000 --- a/vue-rtl/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.vue' diff --git a/vue-rtl/src/components/editor/ui/button/button.vue b/vue-rtl/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-rtl/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/button/index.ts b/vue-rtl/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-rtl/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-rtl/src/components/editor/ui/drop-indicator/drop-indicator.vue b/vue-rtl/src/components/editor/ui/drop-indicator/drop-indicator.vue deleted file mode 100644 index cac51a8629..0000000000 --- a/vue-rtl/src/components/editor/ui/drop-indicator/drop-indicator.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/drop-indicator/index.ts b/vue-rtl/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index b455b1217b..0000000000 --- a/vue-rtl/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator.vue' diff --git a/vue-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/image-upload-popover/index.ts b/vue-rtl/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-rtl/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-rtl/src/components/editor/ui/inline-menu/index.ts b/vue-rtl/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8c72e460c8..0000000000 --- a/vue-rtl/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-rtl/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-rtl/src/components/editor/ui/inline-menu/inline-menu.vue deleted file mode 100644 index cacb76b189..0000000000 --- a/vue-rtl/src/components/editor/ui/inline-menu/inline-menu.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/slash-menu/index.ts b/vue-rtl/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 32d71d61f5..0000000000 --- a/vue-rtl/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu.vue' diff --git a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.vue b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.vue deleted file mode 100644 index 50fc5468fb..0000000000 --- a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-item.vue b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-item.vue deleted file mode 100644 index 2d99363b45..0000000000 --- a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-item.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu.vue b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu.vue deleted file mode 100644 index 87090511e3..0000000000 --- a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu.vue +++ /dev/null @@ -1,106 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/table-handle/index.ts b/vue-rtl/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 0132b96b36..0000000000 --- a/vue-rtl/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle.vue' diff --git a/vue-rtl/src/components/editor/ui/table-handle/table-handle.vue b/vue-rtl/src/components/editor/ui/table-handle/table-handle.vue deleted file mode 100644 index a9921a8f37..0000000000 --- a/vue-rtl/src/components/editor/ui/table-handle/table-handle.vue +++ /dev/null @@ -1,204 +0,0 @@ - - - diff --git a/vue-rtl/src/components/editor/ui/toolbar/index.ts b/vue-rtl/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-rtl/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-rtl/src/components/editor/ui/toolbar/toolbar.vue b/vue-rtl/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-rtl/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-rtl/src/main.ts b/vue-rtl/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-rtl/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-rtl/tsconfig.app.json b/vue-rtl/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-rtl/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-rtl/tsconfig.json b/vue-rtl/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-rtl/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-rtl/tsconfig.node.json b/vue-rtl/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-rtl/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-rtl/vite.config.ts b/vue-rtl/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-rtl/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-save-html/.gitignore b/vue-save-html/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-save-html/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-save-html/README.md b/vue-save-html/README.md deleted file mode 100644 index 35c0a143b2..0000000000 --- a/vue-save-html/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-save-html - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-save-html) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-save-html) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-save-html vue-save-html -cd vue-save-html -npm install -npm run dev -``` diff --git a/vue-save-html/index.html b/vue-save-html/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-save-html/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-save-html/package.json b/vue-save-html/package.json deleted file mode 100644 index 0efcf75897..0000000000 --- a/vue-save-html/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-save-html", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-save-html/src/App.vue b/vue-save-html/src/App.vue deleted file mode 100644 index f815d77bde..0000000000 --- a/vue-save-html/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-save-html/src/app.css b/vue-save-html/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-save-html/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-save-html/src/components/editor/examples/save-html/editor.vue b/vue-save-html/src/components/editor/examples/save-html/editor.vue deleted file mode 100644 index 972df7e21d..0000000000 --- a/vue-save-html/src/components/editor/examples/save-html/editor.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - diff --git a/vue-save-html/src/components/editor/examples/save-html/index.ts b/vue-save-html/src/components/editor/examples/save-html/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-save-html/src/components/editor/examples/save-html/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-save-html/src/main.ts b/vue-save-html/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-save-html/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-save-html/tsconfig.app.json b/vue-save-html/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-save-html/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-save-html/tsconfig.json b/vue-save-html/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-save-html/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-save-html/tsconfig.node.json b/vue-save-html/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-save-html/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-save-html/vite.config.ts b/vue-save-html/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-save-html/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-save-json/.gitignore b/vue-save-json/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-save-json/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-save-json/README.md b/vue-save-json/README.md deleted file mode 100644 index a0b49b9baa..0000000000 --- a/vue-save-json/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-save-json - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-save-json) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-save-json) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-save-json vue-save-json -cd vue-save-json -npm install -npm run dev -``` diff --git a/vue-save-json/index.html b/vue-save-json/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-save-json/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-save-json/package.json b/vue-save-json/package.json deleted file mode 100644 index 01e46e9bcc..0000000000 --- a/vue-save-json/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-save-json", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-save-json/src/App.vue b/vue-save-json/src/App.vue deleted file mode 100644 index 6f603e75b3..0000000000 --- a/vue-save-json/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-save-json/src/app.css b/vue-save-json/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-save-json/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-save-json/src/components/editor/examples/save-json/editor.vue b/vue-save-json/src/components/editor/examples/save-json/editor.vue deleted file mode 100644 index 6e0ca4d065..0000000000 --- a/vue-save-json/src/components/editor/examples/save-json/editor.vue +++ /dev/null @@ -1,75 +0,0 @@ - - - diff --git a/vue-save-json/src/components/editor/examples/save-json/index.ts b/vue-save-json/src/components/editor/examples/save-json/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-save-json/src/components/editor/examples/save-json/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-save-json/src/main.ts b/vue-save-json/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-save-json/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-save-json/tsconfig.app.json b/vue-save-json/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-save-json/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-save-json/tsconfig.json b/vue-save-json/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-save-json/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-save-json/tsconfig.node.json b/vue-save-json/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-save-json/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-save-json/vite.config.ts b/vue-save-json/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-save-json/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-save-markdown/.gitignore b/vue-save-markdown/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-save-markdown/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-save-markdown/README.md b/vue-save-markdown/README.md deleted file mode 100644 index 16101d6f52..0000000000 --- a/vue-save-markdown/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-save-markdown - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-save-markdown) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-save-markdown) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-save-markdown vue-save-markdown -cd vue-save-markdown -npm install -npm run dev -``` diff --git a/vue-save-markdown/index.html b/vue-save-markdown/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-save-markdown/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-save-markdown/package.json b/vue-save-markdown/package.json deleted file mode 100644 index 676d8a9908..0000000000 --- a/vue-save-markdown/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "example-vue-save-markdown", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "rehype-parse": "^9.0.1", - "rehype-remark": "^10.0.1", - "remark-gfm": "^4.0.1", - "remark-html": "^16.0.1", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.5", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-save-markdown/src/App.vue b/vue-save-markdown/src/App.vue deleted file mode 100644 index 0c747fdfbb..0000000000 --- a/vue-save-markdown/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-save-markdown/src/app.css b/vue-save-markdown/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-save-markdown/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-save-markdown/src/components/editor/examples/save-markdown/editor.vue b/vue-save-markdown/src/components/editor/examples/save-markdown/editor.vue deleted file mode 100644 index 179ceda35b..0000000000 --- a/vue-save-markdown/src/components/editor/examples/save-markdown/editor.vue +++ /dev/null @@ -1,79 +0,0 @@ - - - diff --git a/vue-save-markdown/src/components/editor/examples/save-markdown/index.ts b/vue-save-markdown/src/components/editor/examples/save-markdown/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-save-markdown/src/components/editor/examples/save-markdown/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/vue-save-markdown/src/components/editor/examples/save-markdown/markdown.ts deleted file mode 100644 index 3f930adad2..0000000000 --- a/vue-save-markdown/src/components/editor/examples/save-markdown/markdown.ts +++ /dev/null @@ -1,26 +0,0 @@ -import rehypeParse from 'rehype-parse' -import rehypeRemark from 'rehype-remark' -import remarkGfm from 'remark-gfm' -import remarkHtml from 'remark-html' -import remarkParse from 'remark-parse' -import remarkStringify from 'remark-stringify' -import { unified } from 'unified' - -export function markdownFromHTML(html: string): string { - return unified() - .use(rehypeParse) - .use(rehypeRemark) - .use(remarkGfm) - .use(remarkStringify) - .processSync(html) - .toString() -} - -export function htmlFromMarkdown(markdown: string): string { - return unified() - .use(remarkParse) - .use(remarkGfm) - .use(remarkHtml) - .processSync(markdown) - .toString() -} diff --git a/vue-save-markdown/src/main.ts b/vue-save-markdown/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-save-markdown/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-save-markdown/tsconfig.app.json b/vue-save-markdown/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-save-markdown/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-save-markdown/tsconfig.json b/vue-save-markdown/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-save-markdown/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-save-markdown/tsconfig.node.json b/vue-save-markdown/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-save-markdown/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-save-markdown/vite.config.ts b/vue-save-markdown/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-save-markdown/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-search/.gitignore b/vue-search/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-search/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-search/README.md b/vue-search/README.md deleted file mode 100644 index 876b739893..0000000000 --- a/vue-search/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-search - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-search) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-search) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-search vue-search -cd vue-search -npm install -npm run dev -``` diff --git a/vue-search/index.html b/vue-search/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-search/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-search/package.json b/vue-search/package.json deleted file mode 100644 index bccc01fef5..0000000000 --- a/vue-search/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-search", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-search/src/App.vue b/vue-search/src/App.vue deleted file mode 100644 index eae73be827..0000000000 --- a/vue-search/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-search/src/app.css b/vue-search/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-search/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-search/src/components/editor/examples/search/editor.vue b/vue-search/src/components/editor/examples/search/editor.vue deleted file mode 100644 index 8ef91f5a06..0000000000 --- a/vue-search/src/components/editor/examples/search/editor.vue +++ /dev/null @@ -1,40 +0,0 @@ - - - diff --git a/vue-search/src/components/editor/examples/search/extension.ts b/vue-search/src/components/editor/examples/search/extension.ts deleted file mode 100644 index 10ff13f614..0000000000 --- a/vue-search/src/components/editor/examples/search/extension.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineSearchCommands } from 'prosekit/extensions/search' - -export function defineExtension() { - return union(defineBasicExtension(), defineSearchCommands()) -} - -export type EditorExtension = ReturnType diff --git a/vue-search/src/components/editor/examples/search/index.ts b/vue-search/src/components/editor/examples/search/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-search/src/components/editor/examples/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-search/src/components/editor/sample/sample-doc-search.ts b/vue-search/src/components/editor/sample/sample-doc-search.ts deleted file mode 100644 index c8160cca2a..0000000000 --- a/vue-search/src/components/editor/sample/sample-doc-search.ts +++ /dev/null @@ -1,79 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Baa, baa, black sheep,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Have you any wool?', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Yes, sir, yes, sir,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Three bags full;', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'One for the master,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the dame,', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'And one for the little boy', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Who lives down the lane.', - }, - ], - }, - ], -} diff --git a/vue-search/src/components/editor/ui/button/button.vue b/vue-search/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-search/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-search/src/components/editor/ui/button/index.ts b/vue-search/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-search/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-search/src/components/editor/ui/search/index.ts b/vue-search/src/components/editor/ui/search/index.ts deleted file mode 100644 index 39f30055a6..0000000000 --- a/vue-search/src/components/editor/ui/search/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Search } from './search.vue' diff --git a/vue-search/src/components/editor/ui/search/search.vue b/vue-search/src/components/editor/ui/search/search.vue deleted file mode 100644 index 114dd3ec14..0000000000 --- a/vue-search/src/components/editor/ui/search/search.vue +++ /dev/null @@ -1,166 +0,0 @@ - - - diff --git a/vue-search/src/main.ts b/vue-search/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-search/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-search/tsconfig.app.json b/vue-search/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-search/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-search/tsconfig.json b/vue-search/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-search/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-search/tsconfig.node.json b/vue-search/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-search/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-search/vite.config.ts b/vue-search/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-search/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-slash-menu/.gitignore b/vue-slash-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-slash-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-slash-menu/README.md b/vue-slash-menu/README.md deleted file mode 100644 index 62105fa293..0000000000 --- a/vue-slash-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-slash-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-slash-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-slash-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-slash-menu vue-slash-menu -cd vue-slash-menu -npm install -npm run dev -``` diff --git a/vue-slash-menu/index.html b/vue-slash-menu/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-slash-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-slash-menu/package.json b/vue-slash-menu/package.json deleted file mode 100644 index 35b5d2aef6..0000000000 --- a/vue-slash-menu/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-slash-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-slash-menu/src/App.vue b/vue-slash-menu/src/App.vue deleted file mode 100644 index 110f613175..0000000000 --- a/vue-slash-menu/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-slash-menu/src/app.css b/vue-slash-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-slash-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-slash-menu/src/components/editor/examples/slash-menu/editor.vue b/vue-slash-menu/src/components/editor/examples/slash-menu/editor.vue deleted file mode 100644 index a9b813b64c..0000000000 --- a/vue-slash-menu/src/components/editor/examples/slash-menu/editor.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/vue-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/vue-slash-menu/src/components/editor/examples/slash-menu/extension.ts deleted file mode 100644 index 0edda60136..0000000000 --- a/vue-slash-menu/src/components/editor/examples/slash-menu/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ placeholder: 'Press / for commands...' }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-slash-menu/src/components/editor/examples/slash-menu/index.ts b/vue-slash-menu/src/components/editor/examples/slash-menu/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-slash-menu/src/components/editor/examples/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-slash-menu/src/components/editor/ui/slash-menu/index.ts b/vue-slash-menu/src/components/editor/ui/slash-menu/index.ts deleted file mode 100644 index 32d71d61f5..0000000000 --- a/vue-slash-menu/src/components/editor/ui/slash-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as SlashMenu } from './slash-menu.vue' diff --git a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.vue b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.vue deleted file mode 100644 index 50fc5468fb..0000000000 --- a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.vue +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.vue b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.vue deleted file mode 100644 index 2d99363b45..0000000000 --- a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - diff --git a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu.vue b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu.vue deleted file mode 100644 index 87090511e3..0000000000 --- a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu.vue +++ /dev/null @@ -1,106 +0,0 @@ - - - diff --git a/vue-slash-menu/src/main.ts b/vue-slash-menu/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-slash-menu/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-slash-menu/tsconfig.app.json b/vue-slash-menu/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-slash-menu/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-slash-menu/tsconfig.json b/vue-slash-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-slash-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-slash-menu/tsconfig.node.json b/vue-slash-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-slash-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-slash-menu/vite.config.ts b/vue-slash-menu/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-slash-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-strike/.gitignore b/vue-strike/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-strike/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-strike/README.md b/vue-strike/README.md deleted file mode 100644 index 469b22b1fe..0000000000 --- a/vue-strike/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-strike - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-strike) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-strike) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-strike vue-strike -cd vue-strike -npm install -npm run dev -``` diff --git a/vue-strike/index.html b/vue-strike/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-strike/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-strike/package.json b/vue-strike/package.json deleted file mode 100644 index 32f16988af..0000000000 --- a/vue-strike/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-strike", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-strike/src/App.vue b/vue-strike/src/App.vue deleted file mode 100644 index 66e622743e..0000000000 --- a/vue-strike/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-strike/src/app.css b/vue-strike/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-strike/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-strike/src/components/editor/examples/strike/editor.vue b/vue-strike/src/components/editor/examples/strike/editor.vue deleted file mode 100644 index c9dc28c615..0000000000 --- a/vue-strike/src/components/editor/examples/strike/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-strike/src/components/editor/examples/strike/extension.ts b/vue-strike/src/components/editor/examples/strike/extension.ts deleted file mode 100644 index c013303ccc..0000000000 --- a/vue-strike/src/components/editor/examples/strike/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineStrike(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-strike/src/components/editor/examples/strike/index.ts b/vue-strike/src/components/editor/examples/strike/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-strike/src/components/editor/examples/strike/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-strike/src/components/editor/examples/strike/toolbar.vue b/vue-strike/src/components/editor/examples/strike/toolbar.vue deleted file mode 100644 index 57d95ef7ab..0000000000 --- a/vue-strike/src/components/editor/examples/strike/toolbar.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/vue-strike/src/components/editor/sample/sample-doc-strike.ts b/vue-strike/src/components/editor/sample/sample-doc-strike.ts deleted file mode 100644 index 2e025e9b02..0000000000 --- a/vue-strike/src/components/editor/sample/sample-doc-strike.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'This is strike', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/vue-strike/src/components/editor/ui/button/button.vue b/vue-strike/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-strike/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-strike/src/components/editor/ui/button/index.ts b/vue-strike/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-strike/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-strike/src/main.ts b/vue-strike/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-strike/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-strike/tsconfig.app.json b/vue-strike/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-strike/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-strike/tsconfig.json b/vue-strike/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-strike/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-strike/tsconfig.node.json b/vue-strike/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-strike/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-strike/vite.config.ts b/vue-strike/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-strike/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-sub-sup/.gitignore b/vue-sub-sup/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-sub-sup/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-sub-sup/README.md b/vue-sub-sup/README.md deleted file mode 100644 index 16022e1ade..0000000000 --- a/vue-sub-sup/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-sub-sup - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-sub-sup) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-sub-sup) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-sub-sup vue-sub-sup -cd vue-sub-sup -npm install -npm run dev -``` diff --git a/vue-sub-sup/index.html b/vue-sub-sup/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-sub-sup/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-sub-sup/package.json b/vue-sub-sup/package.json deleted file mode 100644 index f7ab3a38f3..0000000000 --- a/vue-sub-sup/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-sub-sup", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-sub-sup/src/App.vue b/vue-sub-sup/src/App.vue deleted file mode 100644 index a9316cfb1c..0000000000 --- a/vue-sub-sup/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-sub-sup/src/app.css b/vue-sub-sup/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-sub-sup/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-sub-sup/src/components/editor/examples/sub-sup/editor.vue b/vue-sub-sup/src/components/editor/examples/sub-sup/editor.vue deleted file mode 100644 index d45c5c2cef..0000000000 --- a/vue-sub-sup/src/components/editor/examples/sub-sup/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/vue-sub-sup/src/components/editor/examples/sub-sup/extension.ts deleted file mode 100644 index bd67245f86..0000000000 --- a/vue-sub-sup/src/components/editor/examples/sub-sup/extension.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineMarkInputRule } from 'prosekit/extensions/input-rule' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineSubscript } from 'prosekit/extensions/subscript' -import { defineSuperscript } from 'prosekit/extensions/superscript' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineSubscript(), - defineSuperscript(), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ - : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, - type: 'subscript', - }), - defineMarkInputRule({ - regex: canUseRegexLookbehind() - ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ - : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, - type: 'superscript', - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-sub-sup/src/components/editor/examples/sub-sup/index.ts b/vue-sub-sup/src/components/editor/examples/sub-sup/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-sub-sup/src/components/editor/examples/sub-sup/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-sub-sup/src/components/editor/examples/sub-sup/toolbar.vue b/vue-sub-sup/src/components/editor/examples/sub-sup/toolbar.vue deleted file mode 100644 index 0d610bdedd..0000000000 --- a/vue-sub-sup/src/components/editor/examples/sub-sup/toolbar.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/vue-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/vue-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts deleted file mode 100644 index 011be750dc..0000000000 --- a/vue-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'H', - }, - { - type: 'text', - marks: [ - { - type: 'subscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: 'O is water. x', - }, - { - type: 'text', - marks: [ - { - type: 'superscript', - }, - ], - text: '2', - }, - { - type: 'text', - text: ' is a square.', - }, - ], - }, - ], -} diff --git a/vue-sub-sup/src/components/editor/ui/button/button.vue b/vue-sub-sup/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-sub-sup/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-sub-sup/src/components/editor/ui/button/index.ts b/vue-sub-sup/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-sub-sup/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-sub-sup/src/main.ts b/vue-sub-sup/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-sub-sup/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-sub-sup/tsconfig.app.json b/vue-sub-sup/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-sub-sup/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-sub-sup/tsconfig.json b/vue-sub-sup/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-sub-sup/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-sub-sup/tsconfig.node.json b/vue-sub-sup/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-sub-sup/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-sub-sup/vite.config.ts b/vue-sub-sup/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-sub-sup/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-table/.gitignore b/vue-table/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-table/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-table/README.md b/vue-table/README.md deleted file mode 100644 index f471ddcd4d..0000000000 --- a/vue-table/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-table - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-table) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-table) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-table vue-table -cd vue-table -npm install -npm run dev -``` diff --git a/vue-table/index.html b/vue-table/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-table/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-table/package.json b/vue-table/package.json deleted file mode 100644 index 8e00b5d10e..0000000000 --- a/vue-table/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-table", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-table/src/App.vue b/vue-table/src/App.vue deleted file mode 100644 index 9d24299530..0000000000 --- a/vue-table/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-table/src/app.css b/vue-table/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-table/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-table/src/components/editor/examples/table/editor.vue b/vue-table/src/components/editor/examples/table/editor.vue deleted file mode 100644 index 333bd4a269..0000000000 --- a/vue-table/src/components/editor/examples/table/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-table/src/components/editor/examples/table/extension.ts b/vue-table/src/components/editor/examples/table/extension.ts deleted file mode 100644 index ee7b142041..0000000000 --- a/vue-table/src/components/editor/examples/table/extension.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineGapCursor } from 'prosekit/extensions/gap-cursor' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineTable(), - defineHistory(), - defineGapCursor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-table/src/components/editor/examples/table/index.ts b/vue-table/src/components/editor/examples/table/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-table/src/components/editor/examples/table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-table/src/components/editor/sample/sample-doc-table.ts b/vue-table/src/components/editor/sample/sample-doc-table.ts deleted file mode 100644 index c737121672..0000000000 --- a/vue-table/src/components/editor/sample/sample-doc-table.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D1', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'A2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'B2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'C2', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'D2', - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], -} diff --git a/vue-table/src/components/editor/ui/table-handle/index.ts b/vue-table/src/components/editor/ui/table-handle/index.ts deleted file mode 100644 index 0132b96b36..0000000000 --- a/vue-table/src/components/editor/ui/table-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TableHandle } from './table-handle.vue' diff --git a/vue-table/src/components/editor/ui/table-handle/table-handle.vue b/vue-table/src/components/editor/ui/table-handle/table-handle.vue deleted file mode 100644 index a9921a8f37..0000000000 --- a/vue-table/src/components/editor/ui/table-handle/table-handle.vue +++ /dev/null @@ -1,204 +0,0 @@ - - - diff --git a/vue-table/src/main.ts b/vue-table/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-table/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-table/tsconfig.app.json b/vue-table/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-table/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-table/tsconfig.json b/vue-table/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-table/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-table/tsconfig.node.json b/vue-table/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-table/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-table/vite.config.ts b/vue-table/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-table/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-text-align/.gitignore b/vue-text-align/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-text-align/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-text-align/README.md b/vue-text-align/README.md deleted file mode 100644 index 87cba2c361..0000000000 --- a/vue-text-align/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-text-align - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-text-align) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-text-align) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-text-align vue-text-align -cd vue-text-align -npm install -npm run dev -``` diff --git a/vue-text-align/index.html b/vue-text-align/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-text-align/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-text-align/package.json b/vue-text-align/package.json deleted file mode 100644 index 38fbfebf9e..0000000000 --- a/vue-text-align/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-text-align", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-text-align/src/App.vue b/vue-text-align/src/App.vue deleted file mode 100644 index f4c3f7bd20..0000000000 --- a/vue-text-align/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-text-align/src/app.css b/vue-text-align/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-text-align/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-text-align/src/components/editor/examples/text-align/editor.vue b/vue-text-align/src/components/editor/examples/text-align/editor.vue deleted file mode 100644 index 8659570703..0000000000 --- a/vue-text-align/src/components/editor/examples/text-align/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-text-align/src/components/editor/examples/text-align/extension.ts b/vue-text-align/src/components/editor/examples/text-align/extension.ts deleted file mode 100644 index f1ae44dc7c..0000000000 --- a/vue-text-align/src/components/editor/examples/text-align/extension.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineTextAlign } from 'prosekit/extensions/text-align' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextAlign({ types: ['paragraph', 'heading'] }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-text-align/src/components/editor/examples/text-align/index.ts b/vue-text-align/src/components/editor/examples/text-align/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-text-align/src/components/editor/examples/text-align/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-text-align/src/components/editor/examples/text-align/toolbar.vue b/vue-text-align/src/components/editor/examples/text-align/toolbar.vue deleted file mode 100644 index d68e9afb13..0000000000 --- a/vue-text-align/src/components/editor/examples/text-align/toolbar.vue +++ /dev/null @@ -1,80 +0,0 @@ - - - diff --git a/vue-text-align/src/components/editor/sample/sample-doc-text-align.ts b/vue-text-align/src/components/editor/sample/sample-doc-text-align.ts deleted file mode 100644 index 0724cea4f7..0000000000 --- a/vue-text-align/src/components/editor/sample/sample-doc-text-align.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Heading', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'left', - }, - content: [ - { - type: 'text', - text: 'First paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'center', - }, - content: [ - { - type: 'text', - text: 'Second paragraph', - }, - ], - }, - { - type: 'paragraph', - attrs: { - textAlign: 'right', - }, - content: [ - { - type: 'text', - text: 'Third paragraph', - }, - ], - }, - ], -} diff --git a/vue-text-align/src/components/editor/ui/button/button.vue b/vue-text-align/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-text-align/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-text-align/src/components/editor/ui/button/index.ts b/vue-text-align/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-text-align/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-text-align/src/main.ts b/vue-text-align/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-text-align/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-text-align/tsconfig.app.json b/vue-text-align/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-text-align/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-text-align/tsconfig.json b/vue-text-align/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-text-align/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-text-align/tsconfig.node.json b/vue-text-align/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-text-align/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-text-align/vite.config.ts b/vue-text-align/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-text-align/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-text-color/.gitignore b/vue-text-color/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-text-color/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-text-color/README.md b/vue-text-color/README.md deleted file mode 100644 index 4576c5b97b..0000000000 --- a/vue-text-color/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-text-color - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-text-color) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-text-color) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-text-color vue-text-color -cd vue-text-color -npm install -npm run dev -``` diff --git a/vue-text-color/index.html b/vue-text-color/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-text-color/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-text-color/package.json b/vue-text-color/package.json deleted file mode 100644 index 47722898a2..0000000000 --- a/vue-text-color/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-text-color", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-text-color/src/App.vue b/vue-text-color/src/App.vue deleted file mode 100644 index a2131cecee..0000000000 --- a/vue-text-color/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-text-color/src/app.css b/vue-text-color/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-text-color/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-text-color/src/components/editor/examples/text-color/editor.vue b/vue-text-color/src/components/editor/examples/text-color/editor.vue deleted file mode 100644 index d5feed6f7d..0000000000 --- a/vue-text-color/src/components/editor/examples/text-color/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-text-color/src/components/editor/examples/text-color/extension.ts b/vue-text-color/src/components/editor/examples/text-color/extension.ts deleted file mode 100644 index d35d9d5c22..0000000000 --- a/vue-text-color/src/components/editor/examples/text-color/extension.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineBackgroundColor } from 'prosekit/extensions/background-color' -import { defineTextColor } from 'prosekit/extensions/text-color' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineTextColor(), - defineBackgroundColor(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-text-color/src/components/editor/examples/text-color/index.ts b/vue-text-color/src/components/editor/examples/text-color/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-text-color/src/components/editor/examples/text-color/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-text-color/src/components/editor/examples/text-color/inline-menu.vue b/vue-text-color/src/components/editor/examples/text-color/inline-menu.vue deleted file mode 100644 index 41660b3614..0000000000 --- a/vue-text-color/src/components/editor/examples/text-color/inline-menu.vue +++ /dev/null @@ -1,142 +0,0 @@ - - - diff --git a/vue-text-color/src/components/editor/sample/sample-doc-text-color.ts b/vue-text-color/src/components/editor/sample/sample-doc-text-color.ts deleted file mode 100644 index a4efe4308d..0000000000 --- a/vue-text-color/src/components/editor/sample/sample-doc-text-color.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#ef4444', - }, - }, - ], - text: 'Select', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#f97316', - }, - }, - ], - text: 'some', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#eab308', - }, - }, - ], - text: 'text', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#22c55e', - }, - }, - ], - text: 'to', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#3b82f6', - }, - }, - ], - text: 'change', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#6366f1', - }, - }, - ], - text: 'the', - }, - { - type: 'text', - text: ' ', - }, - { - type: 'text', - marks: [ - { - type: 'textColor', - attrs: { - color: '#a855f7', - }, - }, - ], - text: 'color', - }, - ], - }, - ], -} diff --git a/vue-text-color/src/components/editor/ui/button/button.vue b/vue-text-color/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-text-color/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-text-color/src/components/editor/ui/button/index.ts b/vue-text-color/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-text-color/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-text-color/src/main.ts b/vue-text-color/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-text-color/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-text-color/tsconfig.app.json b/vue-text-color/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-text-color/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-text-color/tsconfig.json b/vue-text-color/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-text-color/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-text-color/tsconfig.node.json b/vue-text-color/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-text-color/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-text-color/vite.config.ts b/vue-text-color/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-text-color/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-toolbar/.gitignore b/vue-toolbar/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-toolbar/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-toolbar/README.md b/vue-toolbar/README.md deleted file mode 100644 index 801b68f6d0..0000000000 --- a/vue-toolbar/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-toolbar - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-toolbar) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-toolbar) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-toolbar vue-toolbar -cd vue-toolbar -npm install -npm run dev -``` diff --git a/vue-toolbar/index.html b/vue-toolbar/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-toolbar/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-toolbar/package.json b/vue-toolbar/package.json deleted file mode 100644 index ab491eee0f..0000000000 --- a/vue-toolbar/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-toolbar", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-toolbar/src/App.vue b/vue-toolbar/src/App.vue deleted file mode 100644 index f76a007d30..0000000000 --- a/vue-toolbar/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-toolbar/src/app.css b/vue-toolbar/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-toolbar/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-toolbar/src/components/editor/examples/toolbar/editor.vue b/vue-toolbar/src/components/editor/examples/toolbar/editor.vue deleted file mode 100644 index 580cc4ec8f..0000000000 --- a/vue-toolbar/src/components/editor/examples/toolbar/editor.vue +++ /dev/null @@ -1,31 +0,0 @@ - - - diff --git a/vue-toolbar/src/components/editor/examples/toolbar/extension.ts b/vue-toolbar/src/components/editor/examples/toolbar/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/vue-toolbar/src/components/editor/examples/toolbar/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/vue-toolbar/src/components/editor/examples/toolbar/index.ts b/vue-toolbar/src/components/editor/examples/toolbar/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-toolbar/src/components/editor/examples/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-toolbar/src/components/editor/sample/sample-uploader.ts b/vue-toolbar/src/components/editor/sample/sample-uploader.ts deleted file mode 100644 index 8e86d92105..0000000000 --- a/vue-toolbar/src/components/editor/sample/sample-uploader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Uploader } from 'prosekit/extensions/file' - -/** - * Uploads the given file to https://tmpfiles.org/ and returns the URL of the - * uploaded file. - * - * This function is only for demonstration purposes. All uploaded files will be - * deleted by the server after 1 hour. - */ -export const sampleUploader: Uploader = ({ - file, - onProgress, -}): Promise => { - return new Promise((resolve, reject) => { - const xhr = new XMLHttpRequest() - const formData = new FormData() - formData.append('file', file) - - xhr.upload.addEventListener('progress', (event) => { - if (event.lengthComputable) { - onProgress({ - loaded: event.loaded, - total: event.total, - }) - } - }) - - xhr.addEventListener('load', () => { - if (xhr.status === 200) { - try { - const json = JSON.parse(xhr.responseText) as { data: { url: string } } - const url: string = json.data.url.replace( - 'tmpfiles.org/', - 'tmpfiles.org/dl/', - ) - - // Simulate a larger delay - setTimeout(() => resolve(url), 1000) - } catch (error) { - reject(new Error('Failed to parse response', { cause: error })) - } - } else { - reject(new Error(`Upload failed with status ${xhr.status}`)) - } - }) - - xhr.addEventListener('error', () => { - reject(new Error('Upload failed')) - }) - - xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) - xhr.send(formData) - }) -} diff --git a/vue-toolbar/src/components/editor/ui/button/button.vue b/vue-toolbar/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-toolbar/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-toolbar/src/components/editor/ui/button/index.ts b/vue-toolbar/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-toolbar/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/vue-toolbar/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-toolbar/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-toolbar/src/components/editor/ui/toolbar/index.ts b/vue-toolbar/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-toolbar/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-toolbar/src/components/editor/ui/toolbar/toolbar.vue b/vue-toolbar/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-toolbar/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-toolbar/src/main.ts b/vue-toolbar/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-toolbar/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-toolbar/tsconfig.app.json b/vue-toolbar/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-toolbar/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-toolbar/tsconfig.json b/vue-toolbar/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-toolbar/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-toolbar/tsconfig.node.json b/vue-toolbar/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-toolbar/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-toolbar/vite.config.ts b/vue-toolbar/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-toolbar/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-tweet/.gitignore b/vue-tweet/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-tweet/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-tweet/README.md b/vue-tweet/README.md deleted file mode 100644 index 7381d9a7d9..0000000000 --- a/vue-tweet/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-tweet - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-tweet) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-tweet) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-tweet vue-tweet -cd vue-tweet -npm install -npm run dev -``` diff --git a/vue-tweet/index.html b/vue-tweet/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-tweet/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-tweet/package.json b/vue-tweet/package.json deleted file mode 100644 index 8aa7b835df..0000000000 --- a/vue-tweet/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-vue-tweet", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34", - "vue-tweet": "^2.4.0" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-tweet/src/App.vue b/vue-tweet/src/App.vue deleted file mode 100644 index 8516fa911d..0000000000 --- a/vue-tweet/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-tweet/src/app.css b/vue-tweet/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-tweet/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-tweet/src/components/editor/examples/tweet/editor.vue b/vue-tweet/src/components/editor/examples/tweet/editor.vue deleted file mode 100644 index 1a2cf8bd2b..0000000000 --- a/vue-tweet/src/components/editor/examples/tweet/editor.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/vue-tweet/src/components/editor/examples/tweet/extension.ts b/vue-tweet/src/components/editor/examples/tweet/extension.ts deleted file mode 100644 index ec730c0899..0000000000 --- a/vue-tweet/src/components/editor/examples/tweet/extension.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { defineNodeSpec, union } from 'prosekit/core' - -function defineTweetSpec() { - return defineNodeSpec({ - name: 'tweet', - group: 'block', - attrs: { - tweetId: { default: null }, - }, - parseDOM: [ - { - tag: 'iframe[src^="https://platform.twitter.com/embed/Tweet.html"]', - getAttrs: (node) => { - const src = node.getAttribute('src') - const match = src?.match(/id=([^&]+)/) - return { - tweetId: match?.[1] ?? null, - } - }, - }, - ], - toDOM: (node) => { - return [ - 'iframe', - { - src: `https://platform.twitter.com/embed/Tweet.html?id=${node.attrs.tweetId}&theme=dark`, - style: 'height: 300px', - }, - ] - }, - }) -} - -function defineTweet() { - return union(defineTweetSpec()) -} - -export function defineExtension() { - return union(defineBasicExtension(), defineTweet()) -} - -export type EditorExtension = ReturnType diff --git a/vue-tweet/src/components/editor/examples/tweet/index.ts b/vue-tweet/src/components/editor/examples/tweet/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-tweet/src/components/editor/examples/tweet/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-tweet/src/components/editor/examples/tweet/method-select.vue b/vue-tweet/src/components/editor/examples/tweet/method-select.vue deleted file mode 100644 index 2c563692b1..0000000000 --- a/vue-tweet/src/components/editor/examples/tweet/method-select.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-tweet/src/components/editor/examples/tweet/tweet-view.vue b/vue-tweet/src/components/editor/examples/tweet/tweet-view.vue deleted file mode 100644 index b306e5feeb..0000000000 --- a/vue-tweet/src/components/editor/examples/tweet/tweet-view.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - diff --git a/vue-tweet/src/components/editor/sample/sample-doc-tweet.ts b/vue-tweet/src/components/editor/sample/sample-doc-tweet.ts deleted file mode 100644 index f0c0e6ca60..0000000000 --- a/vue-tweet/src/components/editor/sample/sample-doc-tweet.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Render a tweet in your document', - }, - ], - }, - { - type: 'tweet', - attrs: { - tweetId: '20', - }, - }, - ], -} diff --git a/vue-tweet/src/main.ts b/vue-tweet/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-tweet/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-tweet/tsconfig.app.json b/vue-tweet/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-tweet/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-tweet/tsconfig.json b/vue-tweet/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-tweet/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-tweet/tsconfig.node.json b/vue-tweet/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-tweet/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-tweet/vite.config.ts b/vue-tweet/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-tweet/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-typography/.gitignore b/vue-typography/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-typography/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-typography/README.md b/vue-typography/README.md deleted file mode 100644 index 0e7791cd16..0000000000 --- a/vue-typography/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-typography - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-typography) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-typography) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-typography vue-typography -cd vue-typography -npm install -npm run dev -``` diff --git a/vue-typography/index.html b/vue-typography/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-typography/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-typography/package.json b/vue-typography/package.json deleted file mode 100644 index 672072b283..0000000000 --- a/vue-typography/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-vue-typography", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "katex": "^0.16.45", - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-typography/src/App.vue b/vue-typography/src/App.vue deleted file mode 100644 index 9d017ca508..0000000000 --- a/vue-typography/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-typography/src/app.css b/vue-typography/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-typography/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-typography/src/components/editor/examples/typography/editor.vue b/vue-typography/src/components/editor/examples/typography/editor.vue deleted file mode 100644 index 808b26ca30..0000000000 --- a/vue-typography/src/components/editor/examples/typography/editor.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - diff --git a/vue-typography/src/components/editor/examples/typography/extension.ts b/vue-typography/src/components/editor/examples/typography/extension.ts deleted file mode 100644 index 2ffac09de1..0000000000 --- a/vue-typography/src/components/editor/examples/typography/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMath } from 'prosekit/extensions/math' - -import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' - -export function defineExtension() { - return union( - defineBasicExtension(), - defineMath({ - renderMathBlock: renderKaTeXMathBlock, - renderMathInline: renderKaTeXMathInline, - }), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-typography/src/components/editor/examples/typography/index.ts b/vue-typography/src/components/editor/examples/typography/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-typography/src/components/editor/examples/typography/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-typography/src/components/editor/sample/katex.ts b/vue-typography/src/components/editor/sample/katex.ts deleted file mode 100644 index 0f759617cd..0000000000 --- a/vue-typography/src/components/editor/sample/katex.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from 'katex' - -export function renderKaTeXMathBlock(text: string, element: HTMLElement) { - render(text, element, { - displayMode: true, - throwOnError: false, - output: 'mathml', - }) -} - -export function renderKaTeXMathInline(text: string, element: HTMLElement) { - render(text, element, { - displayMode: false, - throwOnError: false, - output: 'mathml', - }) -} diff --git a/vue-typography/src/components/editor/sample/sample-doc-typography.ts b/vue-typography/src/components/editor/sample/sample-doc-typography.ts deleted file mode 100644 index db18b8155c..0000000000 --- a/vue-typography/src/components/editor/sample/sample-doc-typography.ts +++ /dev/null @@ -1,693 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` - -const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'ProseKit Typography', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This example shows the typography styles provided by ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'prosekit/basic/typography.css', - }, - { - type: 'text', - text: '.', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Inline marks', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Text can be formatted in different ways: ', - }, - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'bold text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'italic', - }, - ], - text: 'italic text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'underlined text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'strike', - }, - ], - text: 'strikethrough text', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'code', - }, - ], - text: 'inline code', - }, - { - type: 'text', - text: ', ', - }, - { - type: 'text', - marks: [ - { - type: 'link', - attrs: { - href: 'https://example.com', - target: null, - rel: null, - }, - }, - ], - text: 'links', - }, - { - type: 'text', - text: ',', - }, - { - type: 'hardBreak', - }, - { - type: 'text', - text: 'and hard breaks (Shift+Enter).', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Headings', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 1, - }, - content: [ - { - type: 'text', - text: 'Heading 1', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Heading 2', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 3, - }, - content: [ - { - type: 'text', - text: 'Heading 3', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 4, - }, - content: [ - { - type: 'text', - text: 'Heading 4', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 5, - }, - content: [ - { - type: 'text', - text: 'Heading 5', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 6, - }, - content: [ - { - type: 'text', - text: 'Heading 6', - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Lists', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Here are different types of lists:', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 1', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Unordered list item 2', - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item A', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'bullet', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Nested item B', - }, - ], - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'First ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'ordered', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Second ordered item', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: true, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Completed task', - }, - ], - }, - ], - }, - { - type: 'list', - attrs: { - kind: 'task', - order: null, - checked: false, - collapsed: false, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Pending task', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Blockquotes', - }, - ], - }, - { - type: 'blockquote', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Code Blocks', - }, - ], - }, - { - type: 'codeBlock', - attrs: { - language: '', - }, - content: [ - { - type: 'text', - text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Horizontal Rule', - }, - ], - }, - { - type: 'horizontalRule', - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Images', - }, - ], - }, - { - type: 'image', - attrs: { - src: 'https://static.photos/blurred/640x360/42', - }, - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Tables', - }, - ], - }, - { - type: 'table', - content: [ - { - type: 'tableRow', - content: [ - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 1', - }, - ], - }, - ], - }, - { - type: 'tableHeaderCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Header 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 1', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 2', - }, - ], - }, - ], - }, - ], - }, - { - type: 'tableRow', - content: [ - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 3', - }, - ], - }, - ], - }, - { - type: 'tableCell', - attrs: { - colspan: 1, - rowspan: 1, - colwidth: null, - }, - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Cell 4', - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - type: 'heading', - attrs: { - level: 2, - }, - content: [ - { - type: 'text', - text: 'Math', - }, - ], - }, - { - type: 'paragraph', - content: [ - { type: 'text', text: "Inline math like Euler's identity " }, - { - type: 'mathInline', - content: [{ type: 'text', text: EULER_IDENTITY }], - }, - { type: 'text', text: ' and the quadratic formula ' }, - { - type: 'mathInline', - content: [{ type: 'text', text: QUADRATIC_FORMULA }], - }, - { type: 'text', text: ' can appear within text.' }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Block-level equations are displayed on their own line:', - }, - ], - }, - { - type: 'mathBlock', - content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], - }, - ], -} diff --git a/vue-typography/src/components/editor/ui/block-handle/block-handle.vue b/vue-typography/src/components/editor/ui/block-handle/block-handle.vue deleted file mode 100644 index ba06a1416a..0000000000 --- a/vue-typography/src/components/editor/ui/block-handle/block-handle.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/vue-typography/src/components/editor/ui/block-handle/index.ts b/vue-typography/src/components/editor/ui/block-handle/index.ts deleted file mode 100644 index 2c33eb5726..0000000000 --- a/vue-typography/src/components/editor/ui/block-handle/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as BlockHandle } from './block-handle.vue' diff --git a/vue-typography/src/components/editor/ui/drop-indicator/drop-indicator.vue b/vue-typography/src/components/editor/ui/drop-indicator/drop-indicator.vue deleted file mode 100644 index cac51a8629..0000000000 --- a/vue-typography/src/components/editor/ui/drop-indicator/drop-indicator.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-typography/src/components/editor/ui/drop-indicator/index.ts b/vue-typography/src/components/editor/ui/drop-indicator/index.ts deleted file mode 100644 index b455b1217b..0000000000 --- a/vue-typography/src/components/editor/ui/drop-indicator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as DropIndicator } from './drop-indicator.vue' diff --git a/vue-typography/src/main.ts b/vue-typography/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-typography/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-typography/tsconfig.app.json b/vue-typography/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-typography/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-typography/tsconfig.json b/vue-typography/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-typography/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-typography/tsconfig.node.json b/vue-typography/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-typography/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-typography/vite.config.ts b/vue-typography/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-typography/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-underline/.gitignore b/vue-underline/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-underline/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-underline/README.md b/vue-underline/README.md deleted file mode 100644 index ba351a9a3e..0000000000 --- a/vue-underline/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-underline - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-underline) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-underline) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-underline vue-underline -cd vue-underline -npm install -npm run dev -``` diff --git a/vue-underline/index.html b/vue-underline/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-underline/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-underline/package.json b/vue-underline/package.json deleted file mode 100644 index 931694ad77..0000000000 --- a/vue-underline/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-underline", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-underline/src/App.vue b/vue-underline/src/App.vue deleted file mode 100644 index ecb7590ff1..0000000000 --- a/vue-underline/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-underline/src/app.css b/vue-underline/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-underline/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-underline/src/components/editor/examples/underline/editor.vue b/vue-underline/src/components/editor/examples/underline/editor.vue deleted file mode 100644 index 7a0bc4bcc4..0000000000 --- a/vue-underline/src/components/editor/examples/underline/editor.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-underline/src/components/editor/examples/underline/extension.ts b/vue-underline/src/components/editor/examples/underline/extension.ts deleted file mode 100644 index 16a9b58284..0000000000 --- a/vue-underline/src/components/editor/examples/underline/extension.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineBaseKeymap, union } from 'prosekit/core' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' - -export function defineExtension() { - return union( - defineBaseKeymap(), - defineDoc(), - defineText(), - defineParagraph(), - defineUnderline(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-underline/src/components/editor/examples/underline/index.ts b/vue-underline/src/components/editor/examples/underline/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-underline/src/components/editor/examples/underline/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-underline/src/components/editor/sample/sample-doc-underline.ts b/vue-underline/src/components/editor/sample/sample-doc-underline.ts deleted file mode 100644 index 6af561064b..0000000000 --- a/vue-underline/src/components/editor/sample/sample-doc-underline.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - marks: [ - { - type: 'underline', - }, - ], - text: 'This is underline', - }, - ], - }, - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'This is normal text', - }, - ], - }, - ], -} diff --git a/vue-underline/src/components/editor/ui/button/button.vue b/vue-underline/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-underline/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-underline/src/components/editor/ui/button/index.ts b/vue-underline/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-underline/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-underline/src/components/editor/ui/image-upload-popover/index.ts b/vue-underline/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-underline/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-underline/src/components/editor/ui/toolbar/index.ts b/vue-underline/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-underline/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-underline/src/components/editor/ui/toolbar/toolbar.vue b/vue-underline/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-underline/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-underline/src/main.ts b/vue-underline/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-underline/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-underline/tsconfig.app.json b/vue-underline/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-underline/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-underline/tsconfig.json b/vue-underline/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-underline/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-underline/tsconfig.node.json b/vue-underline/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-underline/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-underline/vite.config.ts b/vue-underline/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-underline/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-unmount/.gitignore b/vue-unmount/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-unmount/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-unmount/README.md b/vue-unmount/README.md deleted file mode 100644 index d746f5a982..0000000000 --- a/vue-unmount/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-unmount - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-unmount) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-unmount) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-unmount vue-unmount -cd vue-unmount -npm install -npm run dev -``` diff --git a/vue-unmount/index.html b/vue-unmount/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-unmount/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-unmount/package.json b/vue-unmount/package.json deleted file mode 100644 index 18e7d1fe62..0000000000 --- a/vue-unmount/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-unmount", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-unmount/src/App.vue b/vue-unmount/src/App.vue deleted file mode 100644 index 9975aabaee..0000000000 --- a/vue-unmount/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-unmount/src/app.css b/vue-unmount/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-unmount/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-unmount/src/components/editor/examples/unmount/editor-component.vue b/vue-unmount/src/components/editor/examples/unmount/editor-component.vue deleted file mode 100644 index 78f726342d..0000000000 --- a/vue-unmount/src/components/editor/examples/unmount/editor-component.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - diff --git a/vue-unmount/src/components/editor/examples/unmount/editor.vue b/vue-unmount/src/components/editor/examples/unmount/editor.vue deleted file mode 100644 index 5f3d19b635..0000000000 --- a/vue-unmount/src/components/editor/examples/unmount/editor.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/vue-unmount/src/components/editor/examples/unmount/extension-component.vue b/vue-unmount/src/components/editor/examples/unmount/extension-component.vue deleted file mode 100644 index 4204dbb234..0000000000 --- a/vue-unmount/src/components/editor/examples/unmount/extension-component.vue +++ /dev/null @@ -1,19 +0,0 @@ - - - diff --git a/vue-unmount/src/components/editor/examples/unmount/index.ts b/vue-unmount/src/components/editor/examples/unmount/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-unmount/src/components/editor/examples/unmount/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-unmount/src/components/editor/ui/button/button.vue b/vue-unmount/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-unmount/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-unmount/src/components/editor/ui/button/index.ts b/vue-unmount/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-unmount/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-unmount/src/components/editor/ui/inline-menu/index.ts b/vue-unmount/src/components/editor/ui/inline-menu/index.ts deleted file mode 100644 index 8c72e460c8..0000000000 --- a/vue-unmount/src/components/editor/ui/inline-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-unmount/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-unmount/src/components/editor/ui/inline-menu/inline-menu.vue deleted file mode 100644 index cacb76b189..0000000000 --- a/vue-unmount/src/components/editor/ui/inline-menu/inline-menu.vue +++ /dev/null @@ -1,219 +0,0 @@ - - - diff --git a/vue-unmount/src/main.ts b/vue-unmount/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-unmount/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-unmount/tsconfig.app.json b/vue-unmount/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-unmount/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-unmount/tsconfig.json b/vue-unmount/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-unmount/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-unmount/tsconfig.node.json b/vue-unmount/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-unmount/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-unmount/vite.config.ts b/vue-unmount/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-unmount/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-user-menu-dynamic/.gitignore b/vue-user-menu-dynamic/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-user-menu-dynamic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-user-menu-dynamic/README.md b/vue-user-menu-dynamic/README.md deleted file mode 100644 index e8b8509188..0000000000 --- a/vue-user-menu-dynamic/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-user-menu-dynamic - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-user-menu-dynamic) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-user-menu-dynamic) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-user-menu-dynamic vue-user-menu-dynamic -cd vue-user-menu-dynamic -npm install -npm run dev -``` diff --git a/vue-user-menu-dynamic/index.html b/vue-user-menu-dynamic/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-user-menu-dynamic/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-user-menu-dynamic/package.json b/vue-user-menu-dynamic/package.json deleted file mode 100644 index 075133939f..0000000000 --- a/vue-user-menu-dynamic/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-user-menu-dynamic", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-user-menu-dynamic/src/App.vue b/vue-user-menu-dynamic/src/App.vue deleted file mode 100644 index 854c270518..0000000000 --- a/vue-user-menu-dynamic/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-user-menu-dynamic/src/app.css b/vue-user-menu-dynamic/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-user-menu-dynamic/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.vue b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.vue deleted file mode 100644 index b645dccef1..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts deleted file mode 100644 index ff2c40b104..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts deleted file mode 100644 index 5c7f71008f..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { Ref } from 'vue' -import { ref, watchEffect } from 'vue' - -import { queryUsers, type User } from '../../sample/sample-query-users' - -/** - * Simulate a user searching with some delay. - */ -export function useUserQuery(query: Ref, enabled: Ref) { - const users = ref([]) - const loading = ref(true) - - watchEffect((onCleanup) => { - if (!enabled.value) { - users.value = [] - return - } - - loading.value = true - let cancelled = false - void queryUsers(query.value).then((result) => { - if (cancelled) { - return - } - users.value = result - loading.value = false - }) - onCleanup(() => { - cancelled = true - }) - }) - - return { loading, users } -} diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.vue b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.vue deleted file mode 100644 index 388dd6ebff..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/vue-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/vue-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts deleted file mode 100644 index ab78fd5525..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { users } from './sample-user-data' - -export interface User { - id: number - name: string -} - -const connectHandlers: VoidFunction[] = [] -let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' - -/** - * A utility function to simulate different network states. Useful for testing. - * - * @internal - */ -export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { - networkStatus = status - if (status !== 'offline') { - connectHandlers.forEach((handler) => handler()) - connectHandlers.length = 0 - } -} - -/** - * Simulate a user searching with some delay. - */ -export async function queryUsers(query: string): Promise { - if (networkStatus === 'offline') { - await new Promise((resolve) => connectHandlers.push(resolve)) - } - if (networkStatus === 'slow') { - await new Promise((resolve) => setTimeout(resolve, 300)) - } - - const normalizedQuery = query.toLowerCase().trim() - const filteredUsers = users - .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) - .slice(0, 10) - return filteredUsers -} diff --git a/vue-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/vue-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/vue-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/vue-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index 29fde1b0b4..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu.vue' diff --git a/vue-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.vue b/vue-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.vue deleted file mode 100644 index 60b4c3131c..0000000000 --- a/vue-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - diff --git a/vue-user-menu-dynamic/src/main.ts b/vue-user-menu-dynamic/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-user-menu-dynamic/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-user-menu-dynamic/tsconfig.app.json b/vue-user-menu-dynamic/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-user-menu-dynamic/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-user-menu-dynamic/tsconfig.json b/vue-user-menu-dynamic/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-user-menu-dynamic/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-user-menu-dynamic/tsconfig.node.json b/vue-user-menu-dynamic/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-user-menu-dynamic/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-user-menu-dynamic/vite.config.ts b/vue-user-menu-dynamic/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-user-menu-dynamic/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-user-menu/.gitignore b/vue-user-menu/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-user-menu/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-user-menu/README.md b/vue-user-menu/README.md deleted file mode 100644 index 27cb75bd33..0000000000 --- a/vue-user-menu/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-user-menu - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-user-menu) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-user-menu) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-user-menu vue-user-menu -cd vue-user-menu -npm install -npm run dev -``` diff --git a/vue-user-menu/index.html b/vue-user-menu/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-user-menu/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-user-menu/package.json b/vue-user-menu/package.json deleted file mode 100644 index eebbb81638..0000000000 --- a/vue-user-menu/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-user-menu", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-user-menu/src/App.vue b/vue-user-menu/src/App.vue deleted file mode 100644 index 161d909b5d..0000000000 --- a/vue-user-menu/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-user-menu/src/app.css b/vue-user-menu/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-user-menu/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-user-menu/src/components/editor/examples/user-menu/editor.vue b/vue-user-menu/src/components/editor/examples/user-menu/editor.vue deleted file mode 100644 index 6f45da5a5b..0000000000 --- a/vue-user-menu/src/components/editor/examples/user-menu/editor.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/vue-user-menu/src/components/editor/examples/user-menu/extension.ts b/vue-user-menu/src/components/editor/examples/user-menu/extension.ts deleted file mode 100644 index 56a97a4779..0000000000 --- a/vue-user-menu/src/components/editor/examples/user-menu/extension.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' -import { defineMention } from 'prosekit/extensions/mention' -import { definePlaceholder } from 'prosekit/extensions/placeholder' - -export function defineExtension() { - return union( - defineBasicExtension(), - definePlaceholder({ - placeholder: 'Type @ to mention someone or # to tag something...', - }), - defineMention(), - ) -} - -export type EditorExtension = ReturnType diff --git a/vue-user-menu/src/components/editor/examples/user-menu/index.ts b/vue-user-menu/src/components/editor/examples/user-menu/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-user-menu/src/components/editor/examples/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-user-menu/src/components/editor/sample/sample-tag-data.ts b/vue-user-menu/src/components/editor/sample/sample-tag-data.ts deleted file mode 100644 index 391cfd4ff4..0000000000 --- a/vue-user-menu/src/components/editor/sample/sample-tag-data.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const tags = [ - { id: 1, label: 'book' }, - { id: 2, label: 'movie' }, - { id: 3, label: 'trip' }, - { id: 4, label: 'music' }, - { id: 5, label: 'art' }, - { id: 6, label: 'food' }, - { id: 7, label: 'sport' }, - { id: 8, label: 'technology' }, - { id: 9, label: 'fashion' }, - { id: 10, label: 'nature' }, -] diff --git a/vue-user-menu/src/components/editor/sample/sample-user-data.ts b/vue-user-menu/src/components/editor/sample/sample-user-data.ts deleted file mode 100644 index 2a90c86c32..0000000000 --- a/vue-user-menu/src/components/editor/sample/sample-user-data.ts +++ /dev/null @@ -1,54 +0,0 @@ -export const users = [ - { id: 1, name: 'Alex' }, - { id: 2, name: 'Alice' }, - { id: 3, name: 'Ben' }, - { id: 4, name: 'Bob' }, - { id: 5, name: 'Charlie' }, - { id: 6, name: 'Cara' }, - { id: 7, name: 'Derek' }, - { id: 8, name: 'Diana' }, - { id: 9, name: 'Ethan' }, - { id: 10, name: 'Eva' }, - { id: 11, name: 'Frank' }, - { id: 12, name: 'Fiona' }, - { id: 13, name: 'George' }, - { id: 14, name: 'Gina' }, - { id: 15, name: 'Harry' }, - { id: 16, name: 'Hannah' }, - { id: 17, name: 'Ivan' }, - { id: 18, name: 'Iris' }, - { id: 19, name: 'Jack' }, - { id: 20, name: 'Jasmine' }, - { id: 21, name: 'Kevin' }, - { id: 22, name: 'Kate' }, - { id: 23, name: 'Leo' }, - { id: 24, name: 'Lily' }, - { id: 25, name: 'Mike' }, - { id: 26, name: 'Mia' }, - { id: 27, name: 'Nathan' }, - { id: 28, name: 'Nancy' }, - { id: 29, name: 'Oscar' }, - { id: 30, name: 'Olivia' }, - { id: 31, name: 'Paul' }, - { id: 32, name: 'Penny' }, - { id: 33, name: 'Quentin' }, - { id: 34, name: 'Queen' }, - { id: 35, name: 'Roger' }, - { id: 36, name: 'Rita' }, - { id: 37, name: 'Sam' }, - { id: 38, name: 'Sara' }, - { id: 39, name: 'Tom' }, - { id: 40, name: 'Tina' }, - { id: 41, name: 'Ulysses' }, - { id: 42, name: 'Una' }, - { id: 43, name: 'Victor' }, - { id: 44, name: 'Vera' }, - { id: 45, name: 'Walter' }, - { id: 46, name: 'Wendy' }, - { id: 47, name: 'Xavier' }, - { id: 48, name: 'Xena' }, - { id: 49, name: 'Yan' }, - { id: 50, name: 'Yvonne' }, - { id: 51, name: 'Zack' }, - { id: 52, name: 'Zara' }, -] diff --git a/vue-user-menu/src/components/editor/ui/tag-menu/index.ts b/vue-user-menu/src/components/editor/ui/tag-menu/index.ts deleted file mode 100644 index 6cb07b1d1c..0000000000 --- a/vue-user-menu/src/components/editor/ui/tag-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as TagMenu } from './tag-menu.vue' diff --git a/vue-user-menu/src/components/editor/ui/tag-menu/tag-menu.vue b/vue-user-menu/src/components/editor/ui/tag-menu/tag-menu.vue deleted file mode 100644 index a8928c53a9..0000000000 --- a/vue-user-menu/src/components/editor/ui/tag-menu/tag-menu.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/vue-user-menu/src/components/editor/ui/user-menu/index.ts b/vue-user-menu/src/components/editor/ui/user-menu/index.ts deleted file mode 100644 index 29fde1b0b4..0000000000 --- a/vue-user-menu/src/components/editor/ui/user-menu/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as UserMenu } from './user-menu.vue' diff --git a/vue-user-menu/src/components/editor/ui/user-menu/user-menu.vue b/vue-user-menu/src/components/editor/ui/user-menu/user-menu.vue deleted file mode 100644 index 60b4c3131c..0000000000 --- a/vue-user-menu/src/components/editor/ui/user-menu/user-menu.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - diff --git a/vue-user-menu/src/main.ts b/vue-user-menu/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-user-menu/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-user-menu/tsconfig.app.json b/vue-user-menu/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-user-menu/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-user-menu/tsconfig.json b/vue-user-menu/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-user-menu/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-user-menu/tsconfig.node.json b/vue-user-menu/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-user-menu/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-user-menu/vite.config.ts b/vue-user-menu/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-user-menu/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-word-counter/.gitignore b/vue-word-counter/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-word-counter/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-word-counter/README.md b/vue-word-counter/README.md deleted file mode 100644 index 9d90b288ee..0000000000 --- a/vue-word-counter/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-word-counter - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-word-counter) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-word-counter) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-word-counter vue-word-counter -cd vue-word-counter -npm install -npm run dev -``` diff --git a/vue-word-counter/index.html b/vue-word-counter/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-word-counter/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-word-counter/package.json b/vue-word-counter/package.json deleted file mode 100644 index f0ac5c9bbf..0000000000 --- a/vue-word-counter/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "example-vue-word-counter", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-word-counter/src/App.vue b/vue-word-counter/src/App.vue deleted file mode 100644 index 473e418f95..0000000000 --- a/vue-word-counter/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-word-counter/src/app.css b/vue-word-counter/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-word-counter/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-word-counter/src/components/editor/examples/word-counter/editor.vue b/vue-word-counter/src/components/editor/examples/word-counter/editor.vue deleted file mode 100644 index 3146088eed..0000000000 --- a/vue-word-counter/src/components/editor/examples/word-counter/editor.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/vue-word-counter/src/components/editor/examples/word-counter/extension.ts b/vue-word-counter/src/components/editor/examples/word-counter/extension.ts deleted file mode 100644 index 1c2b5cbd74..0000000000 --- a/vue-word-counter/src/components/editor/examples/word-counter/extension.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineBasicExtension } from 'prosekit/basic' -import { union } from 'prosekit/core' - -export function defineExtension() { - return union(defineBasicExtension()) -} - -export type EditorExtension = ReturnType diff --git a/vue-word-counter/src/components/editor/examples/word-counter/index.ts b/vue-word-counter/src/components/editor/examples/word-counter/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-word-counter/src/components/editor/examples/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/vue-word-counter/src/components/editor/sample/sample-doc-word-counter.ts deleted file mode 100644 index 0b5d435038..0000000000 --- a/vue-word-counter/src/components/editor/sample/sample-doc-word-counter.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NodeJSON } from 'prosekit/core' - -export const sampleContent: NodeJSON = { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Start typing and observe the word count update below.', - }, - ], - }, - ], -} diff --git a/vue-word-counter/src/components/editor/ui/word-counter/index.ts b/vue-word-counter/src/components/editor/ui/word-counter/index.ts deleted file mode 100644 index 596748a07a..0000000000 --- a/vue-word-counter/src/components/editor/ui/word-counter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as WordCounter } from './word-counter.vue' diff --git a/vue-word-counter/src/components/editor/ui/word-counter/word-counter.vue b/vue-word-counter/src/components/editor/ui/word-counter/word-counter.vue deleted file mode 100644 index 39c3566ad3..0000000000 --- a/vue-word-counter/src/components/editor/ui/word-counter/word-counter.vue +++ /dev/null @@ -1,22 +0,0 @@ - - - diff --git a/vue-word-counter/src/main.ts b/vue-word-counter/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-word-counter/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-word-counter/tsconfig.app.json b/vue-word-counter/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-word-counter/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-word-counter/tsconfig.json b/vue-word-counter/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-word-counter/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-word-counter/tsconfig.node.json b/vue-word-counter/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-word-counter/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-word-counter/vite.config.ts b/vue-word-counter/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-word-counter/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) diff --git a/vue-yjs/.gitignore b/vue-yjs/.gitignore deleted file mode 100644 index 5d6225c6df..0000000000 --- a/vue-yjs/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -dist -.next -.svelte-kit diff --git a/vue-yjs/README.md b/vue-yjs/README.md deleted file mode 100644 index a5b407f183..0000000000 --- a/vue-yjs/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# vue-yjs - -A [ProseKit](https://prosekit.dev) example. - -[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-yjs) -[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-yjs) - -Run the example locally with: - -```bash -npx degit prosekit/examples/vue-yjs vue-yjs -cd vue-yjs -npm install -npm run dev -``` diff --git a/vue-yjs/index.html b/vue-yjs/index.html deleted file mode 100644 index d8952bb9e6..0000000000 --- a/vue-yjs/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - ProseKit + Vue - - -
- - - diff --git a/vue-yjs/package.json b/vue-yjs/package.json deleted file mode 100644 index 357f96321f..0000000000 --- a/vue-yjs/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "example-vue-yjs", - "version": "0.0.0", - "private": true, - "type": "module", - "scripts": { - "build": "vue-tsc -b && vite build", - "dev": "vite", - "preview": "vite preview" - }, - "dependencies": { - "prosekit": "^0.21.0", - "vue": "^3.5.34", - "y-prosemirror": "^1.3.7", - "y-protocols": "^1.0.7", - "y-websocket": "^3.0.0", - "yjs": "^13.6.30" - }, - "devDependencies": { - "@egoist/tailwindcss-icons": "^1.9.2", - "@iconify-json/lucide": "^1.2.107", - "@tailwindcss/vite": "^4.3.0", - "@types/node": "^24.12.4", - "@vitejs/plugin-vue": "^6.0.6", - "@vue/tsconfig": "^0.9.1", - "tailwindcss": "^4.3.0", - "typescript": "^6.0.3", - "vite": "^8.0.13", - "vue-tsc": "^3.2.8" - } -} diff --git a/vue-yjs/src/App.vue b/vue-yjs/src/App.vue deleted file mode 100644 index b40ec3b400..0000000000 --- a/vue-yjs/src/App.vue +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/vue-yjs/src/app.css b/vue-yjs/src/app.css deleted file mode 100644 index ccad1aefaa..0000000000 --- a/vue-yjs/src/app.css +++ /dev/null @@ -1,12 +0,0 @@ -@import 'tailwindcss'; - -@plugin "@egoist/tailwindcss-icons"; - -body { - height: 100svh; - display: grid; - max-width: 900px; - padding: 16px; - margin-left: auto; - margin-right: auto; -} diff --git a/vue-yjs/src/components/editor/examples/yjs/editor-component.vue b/vue-yjs/src/components/editor/examples/yjs/editor-component.vue deleted file mode 100644 index b0dae528b3..0000000000 --- a/vue-yjs/src/components/editor/examples/yjs/editor-component.vue +++ /dev/null @@ -1,38 +0,0 @@ - - - diff --git a/vue-yjs/src/components/editor/examples/yjs/editor.vue b/vue-yjs/src/components/editor/examples/yjs/editor.vue deleted file mode 100644 index f0f9ea0c44..0000000000 --- a/vue-yjs/src/components/editor/examples/yjs/editor.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/vue-yjs/src/components/editor/examples/yjs/extension.ts b/vue-yjs/src/components/editor/examples/yjs/extension.ts deleted file mode 100644 index f1a581932b..0000000000 --- a/vue-yjs/src/components/editor/examples/yjs/extension.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' -import { defineBlockquote } from 'prosekit/extensions/blockquote' -import { defineBold } from 'prosekit/extensions/bold' -import { defineCode } from 'prosekit/extensions/code' -import { defineDoc } from 'prosekit/extensions/doc' -import { defineDropCursor } from 'prosekit/extensions/drop-cursor' -import { defineHeading } from 'prosekit/extensions/heading' -import { defineImage } from 'prosekit/extensions/image' -import { defineItalic } from 'prosekit/extensions/italic' -import { defineLink } from 'prosekit/extensions/link' -import { defineList } from 'prosekit/extensions/list' -import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' -import { defineParagraph } from 'prosekit/extensions/paragraph' -import { defineStrike } from 'prosekit/extensions/strike' -import { defineTable } from 'prosekit/extensions/table' -import { defineText } from 'prosekit/extensions/text' -import { defineUnderline } from 'prosekit/extensions/underline' -import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' -import { defineYjs } from 'prosekit/extensions/yjs' -import type { Awareness } from 'prosekit/extensions/yjs' -import type * as Y from 'yjs' - -export function defineExtension(doc: Y.Doc, awareness: Awareness) { - return union([ - defineDoc(), - defineText(), - defineHeading(), - defineList(), - defineBlockquote(), - defineBaseKeymap(), - defineBaseCommands(), - defineItalic(), - defineBold(), - defineUnderline(), - defineStrike(), - defineCode(), - defineLink(), - defineImage(), - defineParagraph(), - defineDropCursor(), - defineVirtualSelection(), - defineModClickPrevention(), - defineTable(), - defineYjs({ doc, awareness }), - ]) -} - -export type EditorExtension = ReturnType diff --git a/vue-yjs/src/components/editor/examples/yjs/index.ts b/vue-yjs/src/components/editor/examples/yjs/index.ts deleted file mode 100644 index dcc4cb6219..0000000000 --- a/vue-yjs/src/components/editor/examples/yjs/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ExampleEditor } from './editor.vue' diff --git a/vue-yjs/src/components/editor/ui/button/button.vue b/vue-yjs/src/components/editor/ui/button/button.vue deleted file mode 100644 index bfe2720904..0000000000 --- a/vue-yjs/src/components/editor/ui/button/button.vue +++ /dev/null @@ -1,42 +0,0 @@ - - - diff --git a/vue-yjs/src/components/editor/ui/button/index.ts b/vue-yjs/src/components/editor/ui/button/index.ts deleted file mode 100644 index 06b26c2d74..0000000000 --- a/vue-yjs/src/components/editor/ui/button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Button } from './button.vue' diff --git a/vue-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.vue deleted file mode 100644 index da2eee95c5..0000000000 --- a/vue-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.vue +++ /dev/null @@ -1,139 +0,0 @@ - - - diff --git a/vue-yjs/src/components/editor/ui/image-upload-popover/index.ts b/vue-yjs/src/components/editor/ui/image-upload-popover/index.ts deleted file mode 100644 index ec7600958a..0000000000 --- a/vue-yjs/src/components/editor/ui/image-upload-popover/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-yjs/src/components/editor/ui/toolbar/index.ts b/vue-yjs/src/components/editor/ui/toolbar/index.ts deleted file mode 100644 index d4ee621292..0000000000 --- a/vue-yjs/src/components/editor/ui/toolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Toolbar } from './toolbar.vue' diff --git a/vue-yjs/src/components/editor/ui/toolbar/toolbar.vue b/vue-yjs/src/components/editor/ui/toolbar/toolbar.vue deleted file mode 100644 index 9faacc0316..0000000000 --- a/vue-yjs/src/components/editor/ui/toolbar/toolbar.vue +++ /dev/null @@ -1,347 +0,0 @@ - - - diff --git a/vue-yjs/src/main.ts b/vue-yjs/src/main.ts deleted file mode 100644 index 0ed1fdfef8..0000000000 --- a/vue-yjs/src/main.ts +++ /dev/null @@ -1,5 +0,0 @@ -import './app.css' -import { createApp } from 'vue' -import App from './App.vue' - -createApp(App).mount('#app') diff --git a/vue-yjs/tsconfig.app.json b/vue-yjs/tsconfig.app.json deleted file mode 100644 index 7c0e5ef3a8..0000000000 --- a/vue-yjs/tsconfig.app.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "@vue/tsconfig/tsconfig.dom.json", - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", - "types": ["vite/client"], - "lib": ["ES2022", "DOM", "DOM.Iterable"], - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] -} diff --git a/vue-yjs/tsconfig.json b/vue-yjs/tsconfig.json deleted file mode 100644 index 1ffef600d9..0000000000 --- a/vue-yjs/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.app.json" }, - { "path": "./tsconfig.node.json" } - ] -} diff --git a/vue-yjs/tsconfig.node.json b/vue-yjs/tsconfig.node.json deleted file mode 100644 index 8a67f62f4c..0000000000 --- a/vue-yjs/tsconfig.node.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "compilerOptions": { - "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", - "target": "ES2023", - "lib": ["ES2023"], - "module": "ESNext", - "types": ["node"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "moduleDetection": "force", - "noEmit": true, - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "erasableSyntaxOnly": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedSideEffectImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/vue-yjs/vite.config.ts b/vue-yjs/vite.config.ts deleted file mode 100644 index 2e9084402d..0000000000 --- a/vue-yjs/vite.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import tailwindcss from '@tailwindcss/vite' - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [vue(), tailwindcss()], -}) From 25bc9b0798b9aa4e8c6a23ae4b215cc1ba13d2fb Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 16 May 2026 19:08:32 +0000 Subject: [PATCH 2/3] [autofix.ci] apply automated fixes --- lit-block-handle/.gitignore | 4 + lit-block-handle/README.md | 15 + lit-block-handle/index.html | 13 + lit-block-handle/package.json | 24 + lit-block-handle/src/app.css | 12 + lit-block-handle/src/app.ts | 18 + .../editor/examples/block-handle/editor.ts | 99 +++ .../editor/examples/block-handle/extension.ts | 10 + .../editor/examples/block-handle/index.ts | 1 + .../editor/sample/sample-doc-block-handle.ts | 323 ++++++++ .../editor/ui/block-handle/block-handle.ts | 77 ++ .../editor/ui/block-handle/index.ts | 1 + .../ui/code-block-view/code-block-view.ts | 106 +++ .../editor/ui/code-block-view/index.ts | 1 + .../ui/drop-indicator/drop-indicator.ts | 43 ++ .../editor/ui/drop-indicator/index.ts | 1 + .../components/editor/ui/editor-context.ts | 6 + lit-block-handle/src/editor.ts | 18 + lit-block-handle/tsconfig.json | 25 + lit-block-handle/vite.config.ts | 6 + lit-code-block/.gitignore | 4 + lit-code-block/README.md | 15 + lit-code-block/index.html | 13 + lit-code-block/package.json | 24 + lit-code-block/src/app.css | 12 + lit-code-block/src/app.ts | 18 + .../editor/examples/code-block/editor.ts | 87 +++ .../editor/examples/code-block/extension.ts | 24 + .../editor/examples/code-block/index.ts | 1 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../editor/sample/sample-uploader.ts | 54 ++ .../src/components/editor/ui/button/button.ts | 92 +++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.ts | 106 +++ .../editor/ui/code-block-view/index.ts | 1 + .../components/editor/ui/editor-context.ts | 6 + .../image-upload-popover.ts | 200 +++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.ts | 467 ++++++++++++ lit-code-block/src/editor.ts | 18 + lit-code-block/tsconfig.json | 25 + lit-code-block/vite.config.ts | 6 + lit-minimal/.gitignore | 4 + lit-minimal/README.md | 15 + lit-minimal/index.html | 13 + lit-minimal/package.json | 23 + lit-minimal/src/app.css | 12 + lit-minimal/src/app.ts | 18 + .../editor/examples/minimal/editor.ts | 64 ++ .../editor/examples/minimal/index.ts | 1 + lit-minimal/src/editor.ts | 18 + lit-minimal/tsconfig.json | 25 + lit-minimal/vite.config.ts | 6 + lit-slash-menu/.gitignore | 4 + lit-slash-menu/README.md | 15 + lit-slash-menu/index.html | 13 + lit-slash-menu/package.json | 24 + lit-slash-menu/src/app.css | 12 + lit-slash-menu/src/app.ts | 18 + .../editor/examples/slash-menu/editor.ts | 86 +++ .../editor/examples/slash-menu/extension.ts | 12 + .../editor/examples/slash-menu/index.ts | 1 + .../components/editor/ui/editor-context.ts | 6 + .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.ts | 17 + .../editor/ui/slash-menu/slash-menu-item.ts | 44 ++ .../editor/ui/slash-menu/slash-menu.ts | 147 ++++ lit-slash-menu/src/editor.ts | 18 + lit-slash-menu/tsconfig.json | 25 + lit-slash-menu/vite.config.ts | 6 + lit-table/.gitignore | 4 + lit-table/README.md | 15 + lit-table/index.html | 13 + lit-table/package.json | 24 + lit-table/src/app.css | 12 + lit-table/src/app.ts | 18 + .../editor/examples/table/editor.ts | 96 +++ .../editor/examples/table/extension.ts | 20 + .../components/editor/examples/table/index.ts | 1 + .../editor/sample/sample-doc-table.ts | 174 +++++ .../components/editor/ui/editor-context.ts | 6 + .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.ts | 335 +++++++++ lit-table/src/editor.ts | 18 + lit-table/tsconfig.json | 25 + lit-table/vite.config.ts | 6 + lit-toolbar/.gitignore | 4 + lit-toolbar/README.md | 15 + lit-toolbar/index.html | 13 + lit-toolbar/package.json | 24 + lit-toolbar/src/app.css | 12 + lit-toolbar/src/app.ts | 18 + .../editor/examples/toolbar/editor.ts | 85 +++ .../editor/examples/toolbar/extension.ts | 8 + .../editor/examples/toolbar/index.ts | 1 + .../editor/sample/sample-uploader.ts | 54 ++ .../src/components/editor/ui/button/button.ts | 92 +++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/editor-context.ts | 6 + .../image-upload-popover.ts | 200 +++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.ts | 467 ++++++++++++ lit-toolbar/src/editor.ts | 18 + lit-toolbar/tsconfig.json | 25 + lit-toolbar/vite.config.ts | 6 + next-full/.gitignore | 4 + next-full/README.md | 15 + next-full/app/app.css | 12 + next-full/app/layout.tsx | 22 + next-full/app/page.tsx | 9 + next-full/components/editor-dynamic.tsx | 15 + .../editor/examples/full/editor.tsx | 56 ++ .../editor/examples/full/extension.ts | 34 + .../components/editor/examples/full/html.ts | 35 + .../components/editor/examples/full/index.ts | 2 + next-full/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-full.ts | 442 +++++++++++ .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/sample/sample-user-data.ts | 54 ++ .../editor/ui/block-handle/block-handle.tsx | 33 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.tsx | 46 ++ .../components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 39 + .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.tsx | 7 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../editor/ui/image-view/image-view.tsx | 94 +++ .../components/editor/ui/image-view/index.ts | 14 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 11 + .../editor/ui/slash-menu/slash-menu-item.tsx | 23 + .../editor/ui/slash-menu/slash-menu.tsx | 102 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 188 +++++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.tsx | 54 ++ .../components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 64 ++ next-full/next.config.mjs | 4 + next-full/package.json | 29 + next-full/postcss.config.mjs | 8 + next-full/tsconfig.json | 33 + nuxt-full/.gitignore | 4 + nuxt-full/README.md | 15 + nuxt-full/nuxt.config.ts | 12 + nuxt-full/package.json | 27 + nuxt-full/src/app.css | 12 + nuxt-full/src/app.vue | 12 + .../editor/examples/full/editor.vue | 53 ++ .../editor/examples/full/extension.ts | 34 + .../components/editor/examples/full/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-full.ts | 442 +++++++++++ .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/sample/sample-user-data.ts | 54 ++ .../editor/ui/block-handle/block-handle.vue | 39 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.vue | 41 ++ .../editor/ui/code-block-view/index.ts | 12 + .../ui/drop-indicator/drop-indicator.vue | 7 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../editor/ui/image-view/image-view.vue | 97 +++ .../components/editor/ui/image-view/index.ts | 11 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.vue | 219 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.vue | 11 + .../editor/ui/slash-menu/slash-menu-item.vue | 24 + .../editor/ui/slash-menu/slash-menu.vue | 106 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.vue | 204 ++++++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.vue | 59 ++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.vue | 74 ++ nuxt-full/src/editor.vue | 7 + nuxt-full/tsconfig.json | 4 + preact-block-handle/.gitignore | 4 + preact-block-handle/README.md | 15 + preact-block-handle/index.html | 12 + preact-block-handle/package.json | 25 + preact-block-handle/src/App.tsx | 5 + preact-block-handle/src/app.css | 12 + .../editor/examples/block-handle/editor.tsx | 39 + .../editor/examples/block-handle/extension.ts | 10 + .../editor/examples/block-handle/index.ts | 1 + .../editor/sample/sample-doc-block-handle.ts | 323 ++++++++ .../editor/ui/block-handle/block-handle.tsx | 31 + .../editor/ui/block-handle/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 42 ++ .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.tsx | 5 + .../editor/ui/drop-indicator/index.ts | 1 + preact-block-handle/src/main.tsx | 5 + preact-block-handle/tsconfig.app.json | 33 + preact-block-handle/tsconfig.json | 7 + preact-block-handle/tsconfig.node.json | 26 + preact-block-handle/vite.config.ts | 8 + preact-blockquote/.gitignore | 4 + preact-blockquote/README.md | 15 + preact-blockquote/index.html | 12 + preact-blockquote/package.json | 25 + preact-blockquote/src/App.tsx | 5 + preact-blockquote/src/app.css | 12 + .../editor/examples/blockquote/editor.tsx | 30 + .../editor/examples/blockquote/extension.ts | 17 + .../editor/examples/blockquote/index.ts | 1 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-blockquote/src/main.tsx | 5 + preact-blockquote/tsconfig.app.json | 33 + preact-blockquote/tsconfig.json | 7 + preact-blockquote/tsconfig.node.json | 26 + preact-blockquote/vite.config.ts | 8 + preact-bold/.gitignore | 4 + preact-bold/README.md | 15 + preact-bold/index.html | 12 + preact-bold/package.json | 25 + preact-bold/src/App.tsx | 5 + preact-bold/src/app.css | 12 + .../editor/examples/bold/editor.tsx | 37 + .../editor/examples/bold/extension.ts | 17 + .../components/editor/examples/bold/index.ts | 1 + .../editor/sample/sample-doc-bold.ts | 44 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-bold/src/main.tsx | 5 + preact-bold/tsconfig.app.json | 33 + preact-bold/tsconfig.json | 7 + preact-bold/tsconfig.node.json | 26 + preact-bold/vite.config.ts | 8 + preact-change-tracking/.gitignore | 4 + preact-change-tracking/README.md | 15 + preact-change-tracking/index.html | 12 + preact-change-tracking/package.json | 25 + preact-change-tracking/src/App.tsx | 5 + preact-change-tracking/src/app.css | 12 + .../examples/change-tracking/editor-diff.tsx | 30 + .../examples/change-tracking/editor-main.tsx | 37 + .../examples/change-tracking/editor.tsx | 78 ++ .../editor/examples/change-tracking/index.ts | 1 + preact-change-tracking/src/main.tsx | 5 + preact-change-tracking/tsconfig.app.json | 33 + preact-change-tracking/tsconfig.json | 7 + preact-change-tracking/tsconfig.node.json | 26 + preact-change-tracking/vite.config.ts | 8 + preact-code-block-themes/.gitignore | 4 + preact-code-block-themes/README.md | 15 + preact-code-block-themes/index.html | 12 + preact-code-block-themes/package.json | 25 + preact-code-block-themes/src/App.tsx | 5 + preact-code-block-themes/src/app.css | 12 + .../examples/code-block-themes/editor.tsx | 37 + .../examples/code-block-themes/extension.ts | 10 + .../examples/code-block-themes/index.ts | 1 + .../code-block-themes/theme-selector.tsx | 38 + .../examples/code-block-themes/toolbar.tsx | 9 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../ui/code-block-view/code-block-view.tsx | 42 ++ .../editor/ui/code-block-view/index.ts | 15 + preact-code-block-themes/src/main.tsx | 5 + preact-code-block-themes/tsconfig.app.json | 33 + preact-code-block-themes/tsconfig.json | 7 + preact-code-block-themes/tsconfig.node.json | 26 + preact-code-block-themes/vite.config.ts | 8 + preact-code-block/.gitignore | 4 + preact-code-block/README.md | 15 + preact-code-block/index.html | 12 + preact-code-block/package.json | 25 + preact-code-block/src/App.tsx | 5 + preact-code-block/src/app.css | 12 + .../editor/examples/code-block/editor.tsx | 37 + .../editor/examples/code-block/extension.ts | 24 + .../editor/examples/code-block/index.ts | 1 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 42 ++ .../editor/ui/code-block-view/index.ts | 15 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-code-block/src/main.tsx | 5 + preact-code-block/tsconfig.app.json | 33 + preact-code-block/tsconfig.json | 7 + preact-code-block/tsconfig.node.json | 26 + preact-code-block/vite.config.ts | 8 + preact-code/.gitignore | 4 + preact-code/README.md | 15 + preact-code/index.html | 12 + preact-code/package.json | 25 + preact-code/src/App.tsx | 5 + preact-code/src/app.css | 12 + .../editor/examples/code/editor.tsx | 37 + .../editor/examples/code/extension.ts | 17 + .../components/editor/examples/code/index.ts | 1 + .../editor/sample/sample-doc-code.ts | 30 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-code/src/main.tsx | 5 + preact-code/tsconfig.app.json | 33 + preact-code/tsconfig.json | 7 + preact-code/tsconfig.node.json | 26 + preact-code/vite.config.ts | 8 + preact-drop-cursor/.gitignore | 4 + preact-drop-cursor/README.md | 15 + preact-drop-cursor/index.html | 12 + preact-drop-cursor/package.json | 25 + preact-drop-cursor/src/App.tsx | 5 + preact-drop-cursor/src/app.css | 12 + .../editor/examples/drop-cursor/editor.tsx | 35 + .../editor/examples/drop-cursor/extension.ts | 23 + .../editor/examples/drop-cursor/index.ts | 1 + .../editor/sample/sample-doc-drop-cursor.ts | 40 + preact-drop-cursor/src/main.tsx | 5 + preact-drop-cursor/tsconfig.app.json | 33 + preact-drop-cursor/tsconfig.json | 7 + preact-drop-cursor/tsconfig.node.json | 26 + preact-drop-cursor/vite.config.ts | 8 + preact-emoji-rules/.gitignore | 4 + preact-emoji-rules/README.md | 15 + preact-emoji-rules/index.html | 12 + preact-emoji-rules/package.json | 25 + preact-emoji-rules/src/App.tsx | 5 + preact-emoji-rules/src/app.css | 12 + .../editor/examples/emoji-rules/editor.tsx | 28 + .../editor/examples/emoji-rules/emoji.ts | 15 + .../editor/examples/emoji-rules/extension.ts | 15 + .../editor/examples/emoji-rules/index.ts | 1 + preact-emoji-rules/src/main.tsx | 5 + preact-emoji-rules/tsconfig.app.json | 33 + preact-emoji-rules/tsconfig.json | 7 + preact-emoji-rules/tsconfig.node.json | 26 + preact-emoji-rules/vite.config.ts | 8 + preact-full/.gitignore | 4 + preact-full/README.md | 15 + preact-full/index.html | 12 + preact-full/package.json | 26 + preact-full/src/App.tsx | 5 + preact-full/src/app.css | 12 + .../editor/examples/full/editor.tsx | 54 ++ .../editor/examples/full/extension.ts | 34 + .../components/editor/examples/full/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-full.ts | 442 +++++++++++ .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/sample/sample-user-data.ts | 54 ++ .../editor/ui/block-handle/block-handle.tsx | 31 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 42 ++ .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.tsx | 5 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../editor/ui/image-view/image-view.tsx | 95 +++ .../components/editor/ui/image-view/index.ts | 14 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 9 + .../editor/ui/slash-menu/slash-menu-item.tsx | 21 + .../editor/ui/slash-menu/slash-menu.tsx | 100 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 186 +++++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.tsx | 52 ++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 62 ++ preact-full/src/main.tsx | 5 + preact-full/tsconfig.app.json | 33 + preact-full/tsconfig.json | 7 + preact-full/tsconfig.node.json | 26 + preact-full/vite.config.ts | 8 + preact-gap-cursor/.gitignore | 4 + preact-gap-cursor/README.md | 15 + preact-gap-cursor/index.html | 12 + preact-gap-cursor/package.json | 25 + preact-gap-cursor/src/App.tsx | 5 + preact-gap-cursor/src/app.css | 12 + .../editor/examples/gap-cursor/editor.tsx | 34 + .../editor/examples/gap-cursor/extension.ts | 19 + .../editor/examples/gap-cursor/index.ts | 1 + .../editor/sample/sample-doc-gap-cursor.ts | 28 + preact-gap-cursor/src/main.tsx | 5 + preact-gap-cursor/tsconfig.app.json | 33 + preact-gap-cursor/tsconfig.json | 7 + preact-gap-cursor/tsconfig.node.json | 26 + preact-gap-cursor/vite.config.ts | 8 + preact-hard-break/.gitignore | 4 + preact-hard-break/README.md | 15 + preact-hard-break/index.html | 12 + preact-hard-break/package.json | 25 + preact-hard-break/src/App.tsx | 5 + preact-hard-break/src/app.css | 12 + .../editor/examples/hard-break/editor.tsx | 37 + .../editor/examples/hard-break/extension.ts | 17 + .../editor/examples/hard-break/index.ts | 1 + .../editor/examples/hard-break/toolbar.tsx | 31 + .../editor/sample/sample-doc-hard-break.ts | 68 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + preact-hard-break/src/main.tsx | 5 + preact-hard-break/tsconfig.app.json | 33 + preact-hard-break/tsconfig.json | 7 + preact-hard-break/tsconfig.node.json | 26 + preact-hard-break/vite.config.ts | 8 + preact-heading/.gitignore | 4 + preact-heading/README.md | 15 + preact-heading/index.html | 12 + preact-heading/package.json | 25 + preact-heading/src/App.tsx | 5 + preact-heading/src/app.css | 12 + .../editor/examples/heading/editor.tsx | 36 + .../editor/examples/heading/extension.ts | 17 + .../editor/examples/heading/index.ts | 1 + .../editor/sample/sample-doc-heading.ts | 23 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-heading/src/main.tsx | 5 + preact-heading/tsconfig.app.json | 33 + preact-heading/tsconfig.json | 7 + preact-heading/tsconfig.node.json | 26 + preact-heading/vite.config.ts | 8 + preact-highlight/.gitignore | 4 + preact-highlight/README.md | 15 + preact-highlight/index.html | 12 + preact-highlight/package.json | 25 + preact-highlight/src/App.tsx | 5 + preact-highlight/src/app.css | 12 + .../editor/examples/highlight/editor.tsx | 37 + .../editor/examples/highlight/extension.ts | 17 + .../editor/examples/highlight/index.ts | 1 + .../editor/examples/highlight/toolbar.tsx | 32 + .../editor/sample/sample-doc-highlight.ts | 30 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + preact-highlight/src/main.tsx | 5 + preact-highlight/tsconfig.app.json | 33 + preact-highlight/tsconfig.json | 7 + preact-highlight/tsconfig.node.json | 26 + preact-highlight/vite.config.ts | 8 + preact-horizontal-rule/.gitignore | 4 + preact-horizontal-rule/README.md | 15 + preact-horizontal-rule/index.html | 12 + preact-horizontal-rule/package.json | 25 + preact-horizontal-rule/src/App.tsx | 5 + preact-horizontal-rule/src/app.css | 12 + .../examples/horizontal-rule/editor.tsx | 30 + .../examples/horizontal-rule/extension.ts | 17 + .../editor/examples/horizontal-rule/index.ts | 1 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-horizontal-rule/src/main.tsx | 5 + preact-horizontal-rule/tsconfig.app.json | 33 + preact-horizontal-rule/tsconfig.json | 7 + preact-horizontal-rule/tsconfig.node.json | 26 + preact-horizontal-rule/vite.config.ts | 8 + preact-image-view/.gitignore | 4 + preact-image-view/README.md | 15 + preact-image-view/index.html | 12 + preact-image-view/package.json | 25 + preact-image-view/src/App.tsx | 5 + preact-image-view/src/app.css | 12 + .../editor/examples/image-view/editor.tsx | 35 + .../editor/examples/image-view/extension.ts | 18 + .../editor/examples/image-view/index.ts | 1 + .../editor/sample/sample-doc-image.ts | 32 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/image-view/image-view.tsx | 95 +++ .../components/editor/ui/image-view/index.ts | 14 + preact-image-view/src/main.tsx | 5 + preact-image-view/tsconfig.app.json | 33 + preact-image-view/tsconfig.json | 7 + preact-image-view/tsconfig.node.json | 26 + preact-image-view/vite.config.ts | 8 + preact-inline-menu/.gitignore | 4 + preact-inline-menu/README.md | 15 + preact-inline-menu/index.html | 12 + preact-inline-menu/package.json | 25 + preact-inline-menu/src/App.tsx | 5 + preact-inline-menu/src/app.css | 12 + .../editor/examples/inline-menu/editor.tsx | 36 + .../editor/examples/inline-menu/extension.ts | 7 + .../editor/examples/inline-menu/index.ts | 1 + .../editor/sample/sample-doc-inline-menu.ts | 33 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ preact-inline-menu/src/main.tsx | 5 + preact-inline-menu/tsconfig.app.json | 33 + preact-inline-menu/tsconfig.json | 7 + preact-inline-menu/tsconfig.node.json | 26 + preact-inline-menu/vite.config.ts | 8 + preact-italic/.gitignore | 4 + preact-italic/README.md | 15 + preact-italic/index.html | 12 + preact-italic/package.json | 25 + preact-italic/src/App.tsx | 5 + preact-italic/src/app.css | 12 + .../editor/examples/italic/editor.tsx | 37 + .../editor/examples/italic/extension.ts | 17 + .../editor/examples/italic/index.ts | 1 + .../editor/sample/sample-doc-italic.ts | 44 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-italic/src/main.tsx | 5 + preact-italic/tsconfig.app.json | 33 + preact-italic/tsconfig.json | 7 + preact-italic/tsconfig.node.json | 26 + preact-italic/vite.config.ts | 8 + preact-katex/.gitignore | 4 + preact-katex/README.md | 15 + preact-katex/index.html | 12 + preact-katex/package.json | 26 + preact-katex/src/App.tsx | 5 + preact-katex/src/app.css | 12 + .../editor/examples/katex/editor.tsx | 35 + .../editor/examples/katex/extension.ts | 17 + .../components/editor/examples/katex/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-tex.ts | 60 ++ preact-katex/src/main.tsx | 5 + preact-katex/tsconfig.app.json | 33 + preact-katex/tsconfig.json | 7 + preact-katex/tsconfig.node.json | 26 + preact-katex/vite.config.ts | 8 + preact-keymap/.gitignore | 4 + preact-keymap/README.md | 15 + preact-keymap/index.html | 12 + preact-keymap/package.json | 25 + preact-keymap/src/App.tsx | 5 + preact-keymap/src/app.css | 12 + .../editor/examples/keymap/editor.tsx | 52 ++ .../editor/examples/keymap/extension.ts | 8 + .../editor/examples/keymap/index.ts | 1 + .../editor/examples/keymap/toolbar.tsx | 27 + .../examples/keymap/use-submit-keymap.ts | 19 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + preact-keymap/src/main.tsx | 5 + preact-keymap/tsconfig.app.json | 33 + preact-keymap/tsconfig.json | 7 + preact-keymap/tsconfig.node.json | 26 + preact-keymap/vite.config.ts | 8 + preact-link-mark-view/.gitignore | 4 + preact-link-mark-view/README.md | 15 + preact-link-mark-view/index.html | 12 + preact-link-mark-view/package.json | 25 + preact-link-mark-view/src/App.tsx | 5 + preact-link-mark-view/src/app.css | 12 + .../editor/examples/link-mark-view/editor.tsx | 35 + .../examples/link-mark-view/extension.ts | 17 + .../editor/examples/link-mark-view/index.ts | 1 + .../examples/link-mark-view/link-view.tsx | 45 ++ .../sample/sample-doc-link-mark-view.ts | 30 + preact-link-mark-view/src/main.tsx | 5 + preact-link-mark-view/tsconfig.app.json | 33 + preact-link-mark-view/tsconfig.json | 7 + preact-link-mark-view/tsconfig.node.json | 26 + preact-link-mark-view/vite.config.ts | 8 + preact-link/.gitignore | 4 + preact-link/README.md | 15 + preact-link/index.html | 12 + preact-link/package.json | 25 + preact-link/src/App.tsx | 5 + preact-link/src/app.css | 12 + .../editor/examples/link/editor.tsx | 37 + .../editor/examples/link/extension.ts | 17 + .../components/editor/examples/link/index.ts | 1 + .../editor/sample/sample-doc-link.ts | 30 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ preact-link/src/main.tsx | 5 + preact-link/tsconfig.app.json | 33 + preact-link/tsconfig.json | 7 + preact-link/tsconfig.node.json | 26 + preact-link/vite.config.ts | 8 + preact-list-custom-checkbox/.gitignore | 4 + preact-list-custom-checkbox/README.md | 15 + preact-list-custom-checkbox/index.html | 12 + preact-list-custom-checkbox/package.json | 25 + preact-list-custom-checkbox/src/App.tsx | 5 + preact-list-custom-checkbox/src/app.css | 12 + .../list-custom-checkbox/custom-list.css | 75 ++ .../examples/list-custom-checkbox/editor.tsx | 44 ++ .../list-custom-checkbox/extension.ts | 8 + .../examples/list-custom-checkbox/index.ts | 1 + .../sample/sample-doc-list-custom-checkbox.ts | 38 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-list-custom-checkbox/src/main.tsx | 5 + preact-list-custom-checkbox/tsconfig.app.json | 33 + preact-list-custom-checkbox/tsconfig.json | 7 + .../tsconfig.node.json | 26 + preact-list-custom-checkbox/vite.config.ts | 8 + preact-list/.gitignore | 4 + preact-list/README.md | 15 + preact-list/index.html | 12 + preact-list/package.json | 25 + preact-list/src/App.tsx | 5 + preact-list/src/app.css | 12 + .../editor/examples/list/editor.tsx | 37 + .../editor/examples/list/extension.ts | 17 + .../components/editor/examples/list/index.ts | 1 + .../editor/sample/sample-doc-list.ts | 47 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-list/src/main.tsx | 5 + preact-list/tsconfig.app.json | 33 + preact-list/tsconfig.json | 7 + preact-list/tsconfig.node.json | 26 + preact-list/vite.config.ts | 8 + preact-loro/.gitignore | 4 + preact-loro/README.md | 15 + preact-loro/index.html | 12 + preact-loro/package.json | 28 + preact-loro/src/App.tsx | 5 + preact-loro/src/app.css | 12 + .../editor/examples/loro/editor-component.tsx | 36 + .../editor/examples/loro/editor.tsx | 63 ++ .../editor/examples/loro/extension.ts | 47 ++ .../components/editor/examples/loro/index.ts | 1 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-loro/src/main.tsx | 5 + preact-loro/tsconfig.app.json | 33 + preact-loro/tsconfig.json | 7 + preact-loro/tsconfig.node.json | 26 + preact-loro/vite.config.ts | 9 + preact-mark-rule/.gitignore | 4 + preact-mark-rule/README.md | 15 + preact-mark-rule/index.html | 12 + preact-mark-rule/package.json | 25 + preact-mark-rule/src/App.tsx | 5 + preact-mark-rule/src/app.css | 12 + .../editor/examples/mark-rule/editor.tsx | 28 + .../editor/examples/mark-rule/extension.ts | 32 + .../editor/examples/mark-rule/index.ts | 1 + .../editor/examples/mark-rule/issue-link.ts | 32 + preact-mark-rule/src/main.tsx | 5 + preact-mark-rule/tsconfig.app.json | 33 + preact-mark-rule/tsconfig.json | 7 + preact-mark-rule/tsconfig.node.json | 26 + preact-mark-rule/vite.config.ts | 8 + preact-minimal/.gitignore | 4 + preact-minimal/README.md | 15 + preact-minimal/index.html | 12 + preact-minimal/package.json | 25 + preact-minimal/src/App.tsx | 5 + preact-minimal/src/app.css | 12 + .../editor/examples/minimal/editor.tsx | 20 + .../editor/examples/minimal/index.ts | 1 + preact-minimal/src/main.tsx | 5 + preact-minimal/tsconfig.app.json | 33 + preact-minimal/tsconfig.json | 7 + preact-minimal/tsconfig.node.json | 26 + preact-minimal/vite.config.ts | 8 + preact-placeholder/.gitignore | 4 + preact-placeholder/README.md | 15 + preact-placeholder/index.html | 12 + preact-placeholder/package.json | 25 + preact-placeholder/src/App.tsx | 5 + preact-placeholder/src/app.css | 12 + .../editor/examples/placeholder/editor.tsx | 39 + .../editor/examples/placeholder/extension.ts | 12 + .../editor/examples/placeholder/index.ts | 1 + preact-placeholder/src/main.tsx | 5 + preact-placeholder/tsconfig.app.json | 33 + preact-placeholder/tsconfig.json | 7 + preact-placeholder/tsconfig.node.json | 26 + preact-placeholder/vite.config.ts | 8 + preact-readonly/.gitignore | 4 + preact-readonly/README.md | 15 + preact-readonly/index.html | 12 + preact-readonly/package.json | 25 + preact-readonly/src/App.tsx | 5 + preact-readonly/src/app.css | 12 + .../editor/examples/readonly/editor.tsx | 37 + .../editor/examples/readonly/extension.ts | 7 + .../editor/examples/readonly/index.ts | 1 + .../editor/examples/readonly/toolbar.tsx | 19 + .../editor/examples/readonly/use-readonly.ts | 14 + .../editor/sample/sample-doc-readonly.ts | 16 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + preact-readonly/src/main.tsx | 5 + preact-readonly/tsconfig.app.json | 33 + preact-readonly/tsconfig.json | 7 + preact-readonly/tsconfig.node.json | 26 + preact-readonly/vite.config.ts | 8 + preact-rtl/.gitignore | 4 + preact-rtl/README.md | 15 + preact-rtl/index.html | 12 + preact-rtl/package.json | 25 + preact-rtl/src/App.tsx | 5 + preact-rtl/src/app.css | 12 + .../components/editor/examples/rtl/editor.tsx | 50 ++ .../components/editor/examples/rtl/index.ts | 1 + .../editor/sample/sample-doc-rtl.ts | 187 +++++ .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/block-handle/block-handle.tsx | 31 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/drop-indicator/drop-indicator.tsx | 5 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 9 + .../editor/ui/slash-menu/slash-menu-item.tsx | 21 + .../editor/ui/slash-menu/slash-menu.tsx | 100 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 186 +++++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-rtl/src/main.tsx | 5 + preact-rtl/tsconfig.app.json | 33 + preact-rtl/tsconfig.json | 7 + preact-rtl/tsconfig.node.json | 26 + preact-rtl/vite.config.ts | 8 + preact-save-html/.gitignore | 4 + preact-save-html/README.md | 15 + preact-save-html/index.html | 12 + preact-save-html/package.json | 25 + preact-save-html/src/App.tsx | 5 + preact-save-html/src/app.css | 12 + .../editor/examples/save-html/editor.tsx | 74 ++ .../editor/examples/save-html/index.ts | 1 + preact-save-html/src/main.tsx | 5 + preact-save-html/tsconfig.app.json | 33 + preact-save-html/tsconfig.json | 7 + preact-save-html/tsconfig.node.json | 26 + preact-save-html/vite.config.ts | 8 + preact-save-json/.gitignore | 4 + preact-save-json/README.md | 15 + preact-save-json/index.html | 12 + preact-save-json/package.json | 25 + preact-save-json/src/App.tsx | 5 + preact-save-json/src/app.css | 12 + .../editor/examples/save-json/editor.tsx | 74 ++ .../editor/examples/save-json/index.ts | 1 + preact-save-json/src/main.tsx | 5 + preact-save-json/tsconfig.app.json | 33 + preact-save-json/tsconfig.json | 7 + preact-save-json/tsconfig.node.json | 26 + preact-save-json/vite.config.ts | 8 + preact-save-markdown/.gitignore | 4 + preact-save-markdown/README.md | 15 + preact-save-markdown/index.html | 12 + preact-save-markdown/package.json | 32 + preact-save-markdown/src/App.tsx | 5 + preact-save-markdown/src/app.css | 12 + .../editor/examples/save-markdown/editor.tsx | 78 ++ .../editor/examples/save-markdown/index.ts | 1 + .../editor/examples/save-markdown/markdown.ts | 26 + preact-save-markdown/src/main.tsx | 5 + preact-save-markdown/tsconfig.app.json | 33 + preact-save-markdown/tsconfig.json | 7 + preact-save-markdown/tsconfig.node.json | 26 + preact-save-markdown/vite.config.ts | 8 + preact-search/.gitignore | 4 + preact-search/README.md | 15 + preact-search/index.html | 12 + preact-search/package.json | 25 + preact-search/src/App.tsx | 5 + preact-search/src/app.css | 12 + .../editor/examples/search/editor.tsx | 41 ++ .../editor/examples/search/extension.ts | 9 + .../editor/examples/search/index.ts | 1 + .../editor/sample/sample-doc-search.ts | 79 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../src/components/editor/ui/search/index.ts | 1 + .../components/editor/ui/search/search.tsx | 167 +++++ preact-search/src/main.tsx | 5 + preact-search/tsconfig.app.json | 33 + preact-search/tsconfig.json | 7 + preact-search/tsconfig.node.json | 26 + preact-search/vite.config.ts | 8 + preact-slash-menu/.gitignore | 4 + preact-slash-menu/README.md | 15 + preact-slash-menu/index.html | 12 + preact-slash-menu/package.json | 25 + preact-slash-menu/src/App.tsx | 5 + preact-slash-menu/src/app.css | 12 + .../editor/examples/slash-menu/editor.tsx | 31 + .../editor/examples/slash-menu/extension.ts | 12 + .../editor/examples/slash-menu/index.ts | 1 + .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 9 + .../editor/ui/slash-menu/slash-menu-item.tsx | 21 + .../editor/ui/slash-menu/slash-menu.tsx | 100 +++ preact-slash-menu/src/main.tsx | 5 + preact-slash-menu/tsconfig.app.json | 33 + preact-slash-menu/tsconfig.json | 7 + preact-slash-menu/tsconfig.node.json | 26 + preact-slash-menu/vite.config.ts | 8 + preact-strike/.gitignore | 4 + preact-strike/README.md | 15 + preact-strike/index.html | 12 + preact-strike/package.json | 25 + preact-strike/src/App.tsx | 5 + preact-strike/src/app.css | 12 + .../editor/examples/strike/editor.tsx | 37 + .../editor/examples/strike/extension.ts | 17 + .../editor/examples/strike/index.ts | 1 + .../editor/examples/strike/toolbar.tsx | 32 + .../editor/sample/sample-doc-strike.ts | 30 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + preact-strike/src/main.tsx | 5 + preact-strike/tsconfig.app.json | 33 + preact-strike/tsconfig.json | 7 + preact-strike/tsconfig.node.json | 26 + preact-strike/vite.config.ts | 8 + preact-sub-sup/.gitignore | 4 + preact-sub-sup/README.md | 15 + preact-sub-sup/index.html | 12 + preact-sub-sup/package.json | 25 + preact-sub-sup/src/App.tsx | 5 + preact-sub-sup/src/app.css | 12 + .../editor/examples/sub-sup/editor.tsx | 37 + .../editor/examples/sub-sup/extension.ts | 32 + .../editor/examples/sub-sup/index.ts | 1 + .../editor/examples/sub-sup/toolbar.tsx | 44 ++ .../editor/sample/sample-doc-sub-sup.ts | 42 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + preact-sub-sup/src/main.tsx | 5 + preact-sub-sup/tsconfig.app.json | 33 + preact-sub-sup/tsconfig.json | 7 + preact-sub-sup/tsconfig.node.json | 26 + preact-sub-sup/vite.config.ts | 8 + preact-table/.gitignore | 4 + preact-table/README.md | 15 + preact-table/index.html | 12 + preact-table/package.json | 25 + preact-table/src/App.tsx | 5 + preact-table/src/app.css | 12 + .../editor/examples/table/editor.tsx | 37 + .../editor/examples/table/extension.ts | 20 + .../components/editor/examples/table/index.ts | 1 + .../editor/sample/sample-doc-table.ts | 174 +++++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 186 +++++ preact-table/src/main.tsx | 5 + preact-table/tsconfig.app.json | 33 + preact-table/tsconfig.json | 7 + preact-table/tsconfig.node.json | 26 + preact-table/vite.config.ts | 8 + preact-text-align/.gitignore | 4 + preact-text-align/README.md | 15 + preact-text-align/index.html | 12 + preact-text-align/package.json | 25 + preact-text-align/src/App.tsx | 5 + preact-text-align/src/app.css | 12 + .../editor/examples/text-align/editor.tsx | 37 + .../editor/examples/text-align/extension.ts | 12 + .../editor/examples/text-align/index.ts | 1 + .../editor/examples/text-align/toolbar.tsx | 78 ++ .../editor/sample/sample-doc-text-align.ts | 56 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + preact-text-align/src/main.tsx | 5 + preact-text-align/tsconfig.app.json | 33 + preact-text-align/tsconfig.json | 7 + preact-text-align/tsconfig.node.json | 26 + preact-text-align/vite.config.ts | 8 + preact-text-color/.gitignore | 4 + preact-text-color/README.md | 15 + preact-text-color/index.html | 12 + preact-text-color/package.json | 25 + preact-text-color/src/App.tsx | 5 + preact-text-color/src/app.css | 12 + .../editor/examples/text-color/editor.tsx | 37 + .../editor/examples/text-color/extension.ts | 14 + .../editor/examples/text-color/index.ts | 1 + .../examples/text-color/inline-menu.tsx | 145 ++++ .../editor/sample/sample-doc-text-color.ts | 120 +++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + preact-text-color/src/main.tsx | 5 + preact-text-color/tsconfig.app.json | 33 + preact-text-color/tsconfig.json | 7 + preact-text-color/tsconfig.node.json | 26 + preact-text-color/vite.config.ts | 8 + preact-toolbar/.gitignore | 4 + preact-toolbar/README.md | 15 + preact-toolbar/index.html | 12 + preact-toolbar/package.json | 25 + preact-toolbar/src/App.tsx | 5 + preact-toolbar/src/app.css | 12 + .../editor/examples/toolbar/editor.tsx | 32 + .../editor/examples/toolbar/extension.ts | 8 + .../editor/examples/toolbar/index.ts | 1 + .../editor/sample/sample-uploader.ts | 54 ++ .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-toolbar/src/main.tsx | 5 + preact-toolbar/tsconfig.app.json | 33 + preact-toolbar/tsconfig.json | 7 + preact-toolbar/tsconfig.node.json | 26 + preact-toolbar/vite.config.ts | 8 + preact-typography/.gitignore | 4 + preact-typography/README.md | 15 + preact-typography/index.html | 12 + preact-typography/package.json | 26 + preact-typography/src/App.tsx | 5 + preact-typography/src/app.css | 12 + .../editor/examples/typography/editor.tsx | 39 + .../editor/examples/typography/extension.ts | 17 + .../editor/examples/typography/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-typography.ts | 693 ++++++++++++++++++ .../editor/ui/block-handle/block-handle.tsx | 31 + .../editor/ui/block-handle/index.ts | 1 + .../ui/drop-indicator/drop-indicator.tsx | 5 + .../editor/ui/drop-indicator/index.ts | 1 + preact-typography/src/main.tsx | 5 + preact-typography/tsconfig.app.json | 33 + preact-typography/tsconfig.json | 7 + preact-typography/tsconfig.node.json | 26 + preact-typography/vite.config.ts | 8 + preact-underline/.gitignore | 4 + preact-underline/README.md | 15 + preact-underline/index.html | 12 + preact-underline/package.json | 25 + preact-underline/src/App.tsx | 5 + preact-underline/src/app.css | 12 + .../editor/examples/underline/editor.tsx | 37 + .../editor/examples/underline/extension.ts | 17 + .../editor/examples/underline/index.ts | 1 + .../editor/sample/sample-doc-underline.ts | 30 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-underline/src/main.tsx | 5 + preact-underline/tsconfig.app.json | 33 + preact-underline/tsconfig.json | 7 + preact-underline/tsconfig.node.json | 26 + preact-underline/vite.config.ts | 8 + preact-unmount/.gitignore | 4 + preact-unmount/README.md | 15 + preact-unmount/index.html | 12 + preact-unmount/package.json | 25 + preact-unmount/src/App.tsx | 5 + preact-unmount/src/app.css | 12 + .../examples/unmount/editor-component.tsx | 32 + .../editor/examples/unmount/editor.tsx | 44 ++ .../examples/unmount/extension-component.tsx | 14 + .../editor/examples/unmount/index.ts | 1 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ preact-unmount/src/main.tsx | 5 + preact-unmount/tsconfig.app.json | 33 + preact-unmount/tsconfig.json | 7 + preact-unmount/tsconfig.node.json | 26 + preact-unmount/vite.config.ts | 8 + preact-user-menu-dynamic/.gitignore | 4 + preact-user-menu-dynamic/README.md | 15 + preact-user-menu-dynamic/index.html | 12 + preact-user-menu-dynamic/package.json | 25 + preact-user-menu-dynamic/src/App.tsx | 5 + preact-user-menu-dynamic/src/app.css | 12 + .../examples/user-menu-dynamic/editor.tsx | 30 + .../examples/user-menu-dynamic/extension.ts | 16 + .../examples/user-menu-dynamic/index.ts | 1 + .../user-menu-dynamic/use-user-query.ts | 40 + .../user-menu-dynamic/user-menu-dynamic.tsx | 21 + .../editor/sample/sample-query-users.ts | 40 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 62 ++ preact-user-menu-dynamic/src/main.tsx | 5 + preact-user-menu-dynamic/tsconfig.app.json | 33 + preact-user-menu-dynamic/tsconfig.json | 7 + preact-user-menu-dynamic/tsconfig.node.json | 26 + preact-user-menu-dynamic/vite.config.ts | 8 + preact-user-menu/.gitignore | 4 + preact-user-menu/README.md | 15 + preact-user-menu/index.html | 12 + preact-user-menu/package.json | 25 + preact-user-menu/src/App.tsx | 5 + preact-user-menu/src/app.css | 12 + .../editor/examples/user-menu/editor.tsx | 35 + .../editor/examples/user-menu/extension.ts | 16 + .../editor/examples/user-menu/index.ts | 1 + .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.tsx | 52 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 62 ++ preact-user-menu/src/main.tsx | 5 + preact-user-menu/tsconfig.app.json | 33 + preact-user-menu/tsconfig.json | 7 + preact-user-menu/tsconfig.node.json | 26 + preact-user-menu/vite.config.ts | 8 + preact-word-counter/.gitignore | 4 + preact-word-counter/README.md | 15 + preact-word-counter/index.html | 12 + preact-word-counter/package.json | 25 + preact-word-counter/src/App.tsx | 5 + preact-word-counter/src/app.css | 12 + .../editor/examples/word-counter/editor.tsx | 40 + .../editor/examples/word-counter/extension.ts | 8 + .../editor/examples/word-counter/index.ts | 1 + .../editor/sample/sample-doc-word-counter.ts | 16 + .../editor/ui/word-counter/index.ts | 1 + .../editor/ui/word-counter/word-counter.tsx | 22 + preact-word-counter/src/main.tsx | 5 + preact-word-counter/tsconfig.app.json | 33 + preact-word-counter/tsconfig.json | 7 + preact-word-counter/tsconfig.node.json | 26 + preact-word-counter/vite.config.ts | 8 + preact-yjs/.gitignore | 4 + preact-yjs/README.md | 15 + preact-yjs/index.html | 12 + preact-yjs/package.json | 28 + preact-yjs/src/App.tsx | 5 + preact-yjs/src/app.css | 12 + .../editor/examples/yjs/editor-component.tsx | 41 ++ .../components/editor/examples/yjs/editor.tsx | 16 + .../editor/examples/yjs/extension.ts | 48 ++ .../components/editor/examples/yjs/index.ts | 1 + .../components/editor/ui/button/button.tsx | 44 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 144 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 363 +++++++++ preact-yjs/src/main.tsx | 5 + preact-yjs/tsconfig.app.json | 33 + preact-yjs/tsconfig.json | 7 + preact-yjs/tsconfig.node.json | 26 + preact-yjs/vite.config.ts | 8 + react-block-handle/.gitignore | 4 + react-block-handle/README.md | 15 + react-block-handle/index.html | 12 + react-block-handle/package.json | 28 + react-block-handle/src/App.tsx | 5 + react-block-handle/src/app.css | 12 + .../editor/examples/block-handle/editor.tsx | 41 ++ .../editor/examples/block-handle/extension.ts | 10 + .../editor/examples/block-handle/index.ts | 1 + .../editor/sample/sample-doc-block-handle.ts | 323 ++++++++ .../editor/ui/block-handle/block-handle.tsx | 33 + .../editor/ui/block-handle/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 39 + .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.tsx | 7 + .../editor/ui/drop-indicator/index.ts | 1 + react-block-handle/src/main.tsx | 10 + react-block-handle/tsconfig.app.json | 28 + react-block-handle/tsconfig.json | 7 + react-block-handle/tsconfig.node.json | 26 + react-block-handle/vite.config.ts | 8 + react-blockquote/.gitignore | 4 + react-blockquote/README.md | 15 + react-blockquote/index.html | 12 + react-blockquote/package.json | 28 + react-blockquote/src/App.tsx | 5 + react-blockquote/src/app.css | 12 + .../editor/examples/blockquote/editor.tsx | 32 + .../editor/examples/blockquote/extension.ts | 17 + .../editor/examples/blockquote/index.ts | 1 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-blockquote/src/main.tsx | 10 + react-blockquote/tsconfig.app.json | 28 + react-blockquote/tsconfig.json | 7 + react-blockquote/tsconfig.node.json | 26 + react-blockquote/vite.config.ts | 8 + react-bold/.gitignore | 4 + react-bold/README.md | 15 + react-bold/index.html | 12 + react-bold/package.json | 28 + react-bold/src/App.tsx | 5 + react-bold/src/app.css | 12 + .../editor/examples/bold/editor.tsx | 39 + .../editor/examples/bold/extension.ts | 17 + .../components/editor/examples/bold/index.ts | 1 + .../editor/sample/sample-doc-bold.ts | 44 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-bold/src/main.tsx | 10 + react-bold/tsconfig.app.json | 28 + react-bold/tsconfig.json | 7 + react-bold/tsconfig.node.json | 26 + react-bold/vite.config.ts | 8 + react-change-tracking/.gitignore | 4 + react-change-tracking/README.md | 15 + react-change-tracking/index.html | 12 + react-change-tracking/package.json | 28 + react-change-tracking/src/App.tsx | 5 + react-change-tracking/src/app.css | 12 + .../examples/change-tracking/editor-diff.tsx | 32 + .../examples/change-tracking/editor-main.tsx | 39 + .../examples/change-tracking/editor.tsx | 80 ++ .../editor/examples/change-tracking/index.ts | 1 + react-change-tracking/src/main.tsx | 10 + react-change-tracking/tsconfig.app.json | 28 + react-change-tracking/tsconfig.json | 7 + react-change-tracking/tsconfig.node.json | 26 + react-change-tracking/vite.config.ts | 8 + react-code-block-themes/.gitignore | 4 + react-code-block-themes/README.md | 15 + react-code-block-themes/index.html | 12 + react-code-block-themes/package.json | 28 + react-code-block-themes/src/App.tsx | 5 + react-code-block-themes/src/app.css | 12 + .../examples/code-block-themes/editor.tsx | 39 + .../examples/code-block-themes/extension.ts | 10 + .../examples/code-block-themes/index.ts | 1 + .../code-block-themes/theme-selector.tsx | 35 + .../examples/code-block-themes/toolbar.tsx | 11 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../ui/code-block-view/code-block-view.tsx | 39 + .../editor/ui/code-block-view/index.ts | 15 + react-code-block-themes/src/main.tsx | 10 + react-code-block-themes/tsconfig.app.json | 28 + react-code-block-themes/tsconfig.json | 7 + react-code-block-themes/tsconfig.node.json | 26 + react-code-block-themes/vite.config.ts | 8 + react-code-block/.gitignore | 4 + react-code-block/README.md | 15 + react-code-block/index.html | 12 + react-code-block/package.json | 28 + react-code-block/src/App.tsx | 5 + react-code-block/src/app.css | 12 + .../editor/examples/code-block/editor.tsx | 39 + .../editor/examples/code-block/extension.ts | 24 + .../editor/examples/code-block/index.ts | 1 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 39 + .../editor/ui/code-block-view/index.ts | 15 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-code-block/src/main.tsx | 10 + react-code-block/tsconfig.app.json | 28 + react-code-block/tsconfig.json | 7 + react-code-block/tsconfig.node.json | 26 + react-code-block/vite.config.ts | 8 + react-code/.gitignore | 4 + react-code/README.md | 15 + react-code/index.html | 12 + react-code/package.json | 28 + react-code/src/App.tsx | 5 + react-code/src/app.css | 12 + .../editor/examples/code/editor.tsx | 39 + .../editor/examples/code/extension.ts | 17 + .../components/editor/examples/code/index.ts | 1 + .../editor/sample/sample-doc-code.ts | 30 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-code/src/main.tsx | 10 + react-code/tsconfig.app.json | 28 + react-code/tsconfig.json | 7 + react-code/tsconfig.node.json | 26 + react-code/vite.config.ts | 8 + react-drop-cursor/.gitignore | 4 + react-drop-cursor/README.md | 15 + react-drop-cursor/index.html | 12 + react-drop-cursor/package.json | 28 + react-drop-cursor/src/App.tsx | 5 + react-drop-cursor/src/app.css | 12 + .../editor/examples/drop-cursor/editor.tsx | 37 + .../editor/examples/drop-cursor/extension.ts | 23 + .../editor/examples/drop-cursor/index.ts | 1 + .../editor/sample/sample-doc-drop-cursor.ts | 40 + react-drop-cursor/src/main.tsx | 10 + react-drop-cursor/tsconfig.app.json | 28 + react-drop-cursor/tsconfig.json | 7 + react-drop-cursor/tsconfig.node.json | 26 + react-drop-cursor/vite.config.ts | 8 + react-emoji-rules/.gitignore | 4 + react-emoji-rules/README.md | 15 + react-emoji-rules/index.html | 12 + react-emoji-rules/package.json | 28 + react-emoji-rules/src/App.tsx | 5 + react-emoji-rules/src/app.css | 12 + .../editor/examples/emoji-rules/editor.tsx | 30 + .../editor/examples/emoji-rules/emoji.ts | 15 + .../editor/examples/emoji-rules/extension.ts | 15 + .../editor/examples/emoji-rules/index.ts | 1 + react-emoji-rules/src/main.tsx | 10 + react-emoji-rules/tsconfig.app.json | 28 + react-emoji-rules/tsconfig.json | 7 + react-emoji-rules/tsconfig.node.json | 26 + react-emoji-rules/vite.config.ts | 8 + react-full/.gitignore | 4 + react-full/README.md | 15 + react-full/index.html | 12 + react-full/package.json | 29 + react-full/src/App.tsx | 5 + react-full/src/app.css | 12 + .../editor/examples/full/editor.tsx | 56 ++ .../editor/examples/full/extension.ts | 34 + .../components/editor/examples/full/html.ts | 35 + .../components/editor/examples/full/index.ts | 2 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-full.ts | 442 +++++++++++ .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/sample/sample-user-data.ts | 54 ++ .../editor/ui/block-handle/block-handle.tsx | 33 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 39 + .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.tsx | 7 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../editor/ui/image-view/image-view.tsx | 94 +++ .../components/editor/ui/image-view/index.ts | 14 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 11 + .../editor/ui/slash-menu/slash-menu-item.tsx | 23 + .../editor/ui/slash-menu/slash-menu.tsx | 102 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 188 +++++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.tsx | 54 ++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 64 ++ react-full/src/main.tsx | 10 + react-full/tsconfig.app.json | 28 + react-full/tsconfig.json | 7 + react-full/tsconfig.node.json | 26 + react-full/vite.config.ts | 8 + react-gap-cursor/.gitignore | 4 + react-gap-cursor/README.md | 15 + react-gap-cursor/index.html | 12 + react-gap-cursor/package.json | 28 + react-gap-cursor/src/App.tsx | 5 + react-gap-cursor/src/app.css | 12 + .../editor/examples/gap-cursor/editor.tsx | 36 + .../editor/examples/gap-cursor/extension.ts | 19 + .../editor/examples/gap-cursor/index.ts | 1 + .../editor/sample/sample-doc-gap-cursor.ts | 28 + react-gap-cursor/src/main.tsx | 10 + react-gap-cursor/tsconfig.app.json | 28 + react-gap-cursor/tsconfig.json | 7 + react-gap-cursor/tsconfig.node.json | 26 + react-gap-cursor/vite.config.ts | 8 + react-hard-break/.gitignore | 4 + react-hard-break/README.md | 15 + react-hard-break/index.html | 12 + react-hard-break/package.json | 28 + react-hard-break/src/App.tsx | 5 + react-hard-break/src/app.css | 12 + .../editor/examples/hard-break/editor.tsx | 39 + .../editor/examples/hard-break/extension.ts | 17 + .../editor/examples/hard-break/index.ts | 1 + .../editor/examples/hard-break/toolbar.tsx | 33 + .../editor/sample/sample-doc-hard-break.ts | 68 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + react-hard-break/src/main.tsx | 10 + react-hard-break/tsconfig.app.json | 28 + react-hard-break/tsconfig.json | 7 + react-hard-break/tsconfig.node.json | 26 + react-hard-break/vite.config.ts | 8 + react-heading/.gitignore | 4 + react-heading/README.md | 15 + react-heading/index.html | 12 + react-heading/package.json | 28 + react-heading/src/App.tsx | 5 + react-heading/src/app.css | 12 + .../editor/examples/heading/editor.tsx | 38 + .../editor/examples/heading/extension.ts | 17 + .../editor/examples/heading/index.ts | 1 + .../editor/sample/sample-doc-heading.ts | 23 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-heading/src/main.tsx | 10 + react-heading/tsconfig.app.json | 28 + react-heading/tsconfig.json | 7 + react-heading/tsconfig.node.json | 26 + react-heading/vite.config.ts | 8 + react-highlight/.gitignore | 4 + react-highlight/README.md | 15 + react-highlight/index.html | 12 + react-highlight/package.json | 28 + react-highlight/src/App.tsx | 5 + react-highlight/src/app.css | 12 + .../editor/examples/highlight/editor.tsx | 39 + .../editor/examples/highlight/extension.ts | 17 + .../editor/examples/highlight/index.ts | 1 + .../editor/examples/highlight/toolbar.tsx | 34 + .../editor/sample/sample-doc-highlight.ts | 30 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + react-highlight/src/main.tsx | 10 + react-highlight/tsconfig.app.json | 28 + react-highlight/tsconfig.json | 7 + react-highlight/tsconfig.node.json | 26 + react-highlight/vite.config.ts | 8 + react-horizontal-rule/.gitignore | 4 + react-horizontal-rule/README.md | 15 + react-horizontal-rule/index.html | 12 + react-horizontal-rule/package.json | 28 + react-horizontal-rule/src/App.tsx | 5 + react-horizontal-rule/src/app.css | 12 + .../examples/horizontal-rule/editor.tsx | 32 + .../examples/horizontal-rule/extension.ts | 17 + .../editor/examples/horizontal-rule/index.ts | 1 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-horizontal-rule/src/main.tsx | 10 + react-horizontal-rule/tsconfig.app.json | 28 + react-horizontal-rule/tsconfig.json | 7 + react-horizontal-rule/tsconfig.node.json | 26 + react-horizontal-rule/vite.config.ts | 8 + react-image-view/.gitignore | 4 + react-image-view/README.md | 15 + react-image-view/index.html | 12 + react-image-view/package.json | 28 + react-image-view/src/App.tsx | 5 + react-image-view/src/app.css | 12 + .../editor/examples/image-view/editor.tsx | 37 + .../editor/examples/image-view/extension.ts | 18 + .../editor/examples/image-view/index.ts | 1 + .../editor/sample/sample-doc-image.ts | 32 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/image-view/image-view.tsx | 94 +++ .../components/editor/ui/image-view/index.ts | 14 + react-image-view/src/main.tsx | 10 + react-image-view/tsconfig.app.json | 28 + react-image-view/tsconfig.json | 7 + react-image-view/tsconfig.node.json | 26 + react-image-view/vite.config.ts | 8 + react-inline-menu/.gitignore | 4 + react-inline-menu/README.md | 15 + react-inline-menu/index.html | 12 + react-inline-menu/package.json | 28 + react-inline-menu/src/App.tsx | 5 + react-inline-menu/src/app.css | 12 + .../editor/examples/inline-menu/editor.tsx | 38 + .../editor/examples/inline-menu/extension.ts | 7 + .../editor/examples/inline-menu/index.ts | 1 + .../editor/sample/sample-doc-inline-menu.ts | 33 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ react-inline-menu/src/main.tsx | 10 + react-inline-menu/tsconfig.app.json | 28 + react-inline-menu/tsconfig.json | 7 + react-inline-menu/tsconfig.node.json | 26 + react-inline-menu/vite.config.ts | 8 + react-italic/.gitignore | 4 + react-italic/README.md | 15 + react-italic/index.html | 12 + react-italic/package.json | 28 + react-italic/src/App.tsx | 5 + react-italic/src/app.css | 12 + .../editor/examples/italic/editor.tsx | 39 + .../editor/examples/italic/extension.ts | 17 + .../editor/examples/italic/index.ts | 1 + .../editor/sample/sample-doc-italic.ts | 44 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-italic/src/main.tsx | 10 + react-italic/tsconfig.app.json | 28 + react-italic/tsconfig.json | 7 + react-italic/tsconfig.node.json | 26 + react-italic/vite.config.ts | 8 + react-katex/.gitignore | 4 + react-katex/README.md | 15 + react-katex/index.html | 12 + react-katex/package.json | 29 + react-katex/src/App.tsx | 5 + react-katex/src/app.css | 12 + .../editor/examples/katex/editor.tsx | 37 + .../editor/examples/katex/extension.ts | 17 + .../components/editor/examples/katex/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-tex.ts | 60 ++ react-katex/src/main.tsx | 10 + react-katex/tsconfig.app.json | 28 + react-katex/tsconfig.json | 7 + react-katex/tsconfig.node.json | 26 + react-katex/vite.config.ts | 8 + react-keymap/.gitignore | 4 + react-keymap/README.md | 15 + react-keymap/index.html | 12 + react-keymap/package.json | 28 + react-keymap/src/App.tsx | 5 + react-keymap/src/app.css | 12 + .../editor/examples/keymap/editor.tsx | 54 ++ .../editor/examples/keymap/extension.ts | 8 + .../editor/examples/keymap/index.ts | 1 + .../editor/examples/keymap/toolbar.tsx | 29 + .../examples/keymap/use-submit-keymap.ts | 19 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + react-keymap/src/main.tsx | 10 + react-keymap/tsconfig.app.json | 28 + react-keymap/tsconfig.json | 7 + react-keymap/tsconfig.node.json | 26 + react-keymap/vite.config.ts | 8 + react-link-mark-view/.gitignore | 4 + react-link-mark-view/README.md | 15 + react-link-mark-view/index.html | 12 + react-link-mark-view/package.json | 28 + react-link-mark-view/src/App.tsx | 5 + react-link-mark-view/src/app.css | 12 + .../editor/examples/link-mark-view/editor.tsx | 37 + .../examples/link-mark-view/extension.ts | 17 + .../editor/examples/link-mark-view/index.ts | 1 + .../examples/link-mark-view/link-view.tsx | 47 ++ .../sample/sample-doc-link-mark-view.ts | 30 + react-link-mark-view/src/main.tsx | 10 + react-link-mark-view/tsconfig.app.json | 28 + react-link-mark-view/tsconfig.json | 7 + react-link-mark-view/tsconfig.node.json | 26 + react-link-mark-view/vite.config.ts | 8 + react-link/.gitignore | 4 + react-link/README.md | 15 + react-link/index.html | 12 + react-link/package.json | 28 + react-link/src/App.tsx | 5 + react-link/src/app.css | 12 + .../editor/examples/link/editor.tsx | 39 + .../editor/examples/link/extension.ts | 17 + .../components/editor/examples/link/index.ts | 1 + .../editor/sample/sample-doc-link.ts | 30 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ react-link/src/main.tsx | 10 + react-link/tsconfig.app.json | 28 + react-link/tsconfig.json | 7 + react-link/tsconfig.node.json | 26 + react-link/vite.config.ts | 8 + react-list-custom-checkbox/.gitignore | 4 + react-list-custom-checkbox/README.md | 15 + react-list-custom-checkbox/index.html | 12 + react-list-custom-checkbox/package.json | 28 + react-list-custom-checkbox/src/App.tsx | 5 + react-list-custom-checkbox/src/app.css | 12 + .../list-custom-checkbox/custom-list.css | 75 ++ .../examples/list-custom-checkbox/editor.tsx | 46 ++ .../list-custom-checkbox/extension.ts | 8 + .../examples/list-custom-checkbox/index.ts | 1 + .../sample/sample-doc-list-custom-checkbox.ts | 38 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-list-custom-checkbox/src/main.tsx | 10 + react-list-custom-checkbox/tsconfig.app.json | 28 + react-list-custom-checkbox/tsconfig.json | 7 + react-list-custom-checkbox/tsconfig.node.json | 26 + react-list-custom-checkbox/vite.config.ts | 8 + react-list/.gitignore | 4 + react-list/README.md | 15 + react-list/index.html | 12 + react-list/package.json | 28 + react-list/src/App.tsx | 5 + react-list/src/app.css | 12 + .../editor/examples/list/editor.tsx | 39 + .../editor/examples/list/extension.ts | 17 + .../components/editor/examples/list/index.ts | 1 + .../editor/sample/sample-doc-list.ts | 47 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-list/src/main.tsx | 10 + react-list/tsconfig.app.json | 28 + react-list/tsconfig.json | 7 + react-list/tsconfig.node.json | 26 + react-list/vite.config.ts | 8 + react-loro/.gitignore | 4 + react-loro/README.md | 15 + react-loro/index.html | 12 + react-loro/package.json | 31 + react-loro/src/App.tsx | 5 + react-loro/src/app.css | 12 + .../editor/examples/loro/editor-component.tsx | 38 + .../editor/examples/loro/editor.tsx | 65 ++ .../editor/examples/loro/extension.ts | 47 ++ .../components/editor/examples/loro/index.ts | 1 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-loro/src/main.tsx | 10 + react-loro/tsconfig.app.json | 28 + react-loro/tsconfig.json | 7 + react-loro/tsconfig.node.json | 26 + react-loro/vite.config.ts | 9 + react-mark-rule/.gitignore | 4 + react-mark-rule/README.md | 15 + react-mark-rule/index.html | 12 + react-mark-rule/package.json | 28 + react-mark-rule/src/App.tsx | 5 + react-mark-rule/src/app.css | 12 + .../editor/examples/mark-rule/editor.tsx | 30 + .../editor/examples/mark-rule/extension.ts | 32 + .../editor/examples/mark-rule/index.ts | 1 + .../editor/examples/mark-rule/issue-link.ts | 32 + react-mark-rule/src/main.tsx | 10 + react-mark-rule/tsconfig.app.json | 28 + react-mark-rule/tsconfig.json | 7 + react-mark-rule/tsconfig.node.json | 26 + react-mark-rule/vite.config.ts | 8 + react-minimal/.gitignore | 4 + react-minimal/README.md | 15 + react-minimal/index.html | 12 + react-minimal/package.json | 28 + react-minimal/src/App.tsx | 5 + react-minimal/src/app.css | 12 + .../editor/examples/minimal/editor.tsx | 22 + .../editor/examples/minimal/index.ts | 1 + react-minimal/src/main.tsx | 10 + react-minimal/tsconfig.app.json | 28 + react-minimal/tsconfig.json | 7 + react-minimal/tsconfig.node.json | 26 + react-minimal/vite.config.ts | 8 + react-page/.gitignore | 4 + react-page/README.md | 15 + react-page/index.html | 12 + react-page/package.json | 28 + react-page/src/App.tsx | 5 + react-page/src/app.css | 12 + .../editor/examples/page/editor.tsx | 49 ++ .../editor/examples/page/extension.ts | 9 + .../components/editor/examples/page/index.ts | 1 + .../editor/examples/page/paper-controller.tsx | 142 ++++ .../components/editor/examples/page/zoom.css | 9 + .../editor/sample/sample-doc-page.ts | 98 +++ react-page/src/main.tsx | 10 + react-page/tsconfig.app.json | 28 + react-page/tsconfig.json | 7 + react-page/tsconfig.node.json | 26 + react-page/vite.config.ts | 8 + react-placeholder/.gitignore | 4 + react-placeholder/README.md | 15 + react-placeholder/index.html | 12 + react-placeholder/package.json | 28 + react-placeholder/src/App.tsx | 5 + react-placeholder/src/app.css | 12 + .../editor/examples/placeholder/editor.tsx | 41 ++ .../editor/examples/placeholder/extension.ts | 12 + .../editor/examples/placeholder/index.ts | 1 + react-placeholder/src/main.tsx | 10 + react-placeholder/tsconfig.app.json | 28 + react-placeholder/tsconfig.json | 7 + react-placeholder/tsconfig.node.json | 26 + react-placeholder/vite.config.ts | 8 + react-readonly/.gitignore | 4 + react-readonly/README.md | 15 + react-readonly/index.html | 12 + react-readonly/package.json | 28 + react-readonly/src/App.tsx | 5 + react-readonly/src/app.css | 12 + .../editor/examples/readonly/editor.tsx | 39 + .../editor/examples/readonly/extension.ts | 7 + .../editor/examples/readonly/index.ts | 1 + .../editor/examples/readonly/toolbar.tsx | 21 + .../editor/examples/readonly/use-readonly.ts | 14 + .../editor/sample/sample-doc-readonly.ts | 16 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + react-readonly/src/main.tsx | 10 + react-readonly/tsconfig.app.json | 28 + react-readonly/tsconfig.json | 7 + react-readonly/tsconfig.node.json | 26 + react-readonly/vite.config.ts | 8 + react-rtl/.gitignore | 4 + react-rtl/README.md | 15 + react-rtl/index.html | 12 + react-rtl/package.json | 28 + react-rtl/src/App.tsx | 5 + react-rtl/src/app.css | 12 + .../components/editor/examples/rtl/editor.tsx | 52 ++ .../components/editor/examples/rtl/index.ts | 1 + .../editor/sample/sample-doc-rtl.ts | 187 +++++ .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/block-handle/block-handle.tsx | 33 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/drop-indicator/drop-indicator.tsx | 7 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 11 + .../editor/ui/slash-menu/slash-menu-item.tsx | 23 + .../editor/ui/slash-menu/slash-menu.tsx | 102 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 188 +++++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-rtl/src/main.tsx | 10 + react-rtl/tsconfig.app.json | 28 + react-rtl/tsconfig.json | 7 + react-rtl/tsconfig.node.json | 26 + react-rtl/vite.config.ts | 8 + react-save-html/.gitignore | 4 + react-save-html/README.md | 15 + react-save-html/index.html | 12 + react-save-html/package.json | 28 + react-save-html/src/App.tsx | 5 + react-save-html/src/app.css | 12 + .../editor/examples/save-html/editor.tsx | 76 ++ .../editor/examples/save-html/index.ts | 1 + react-save-html/src/main.tsx | 10 + react-save-html/tsconfig.app.json | 28 + react-save-html/tsconfig.json | 7 + react-save-html/tsconfig.node.json | 26 + react-save-html/vite.config.ts | 8 + react-save-json/.gitignore | 4 + react-save-json/README.md | 15 + react-save-json/index.html | 12 + react-save-json/package.json | 28 + react-save-json/src/App.tsx | 5 + react-save-json/src/app.css | 12 + .../editor/examples/save-json/editor.tsx | 76 ++ .../editor/examples/save-json/index.ts | 1 + react-save-json/src/main.tsx | 10 + react-save-json/tsconfig.app.json | 28 + react-save-json/tsconfig.json | 7 + react-save-json/tsconfig.node.json | 26 + react-save-json/vite.config.ts | 8 + react-save-markdown/.gitignore | 4 + react-save-markdown/README.md | 15 + react-save-markdown/index.html | 12 + react-save-markdown/package.json | 35 + react-save-markdown/src/App.tsx | 5 + react-save-markdown/src/app.css | 12 + .../editor/examples/save-markdown/editor.tsx | 80 ++ .../editor/examples/save-markdown/index.ts | 1 + .../editor/examples/save-markdown/markdown.ts | 26 + react-save-markdown/src/main.tsx | 10 + react-save-markdown/tsconfig.app.json | 28 + react-save-markdown/tsconfig.json | 7 + react-save-markdown/tsconfig.node.json | 26 + react-save-markdown/vite.config.ts | 8 + react-search/.gitignore | 4 + react-search/README.md | 15 + react-search/index.html | 12 + react-search/package.json | 28 + react-search/src/App.tsx | 5 + react-search/src/app.css | 12 + .../editor/examples/search/editor.tsx | 43 ++ .../editor/examples/search/extension.ts | 9 + .../editor/examples/search/index.ts | 1 + .../editor/sample/sample-doc-search.ts | 79 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../src/components/editor/ui/search/index.ts | 1 + .../components/editor/ui/search/search.tsx | 169 +++++ react-search/src/main.tsx | 10 + react-search/tsconfig.app.json | 28 + react-search/tsconfig.json | 7 + react-search/tsconfig.node.json | 26 + react-search/vite.config.ts | 8 + react-slash-menu/.gitignore | 4 + react-slash-menu/README.md | 15 + react-slash-menu/index.html | 12 + react-slash-menu/package.json | 28 + react-slash-menu/src/App.tsx | 5 + react-slash-menu/src/app.css | 12 + .../editor/examples/slash-menu/editor.tsx | 33 + .../editor/examples/slash-menu/extension.ts | 12 + .../editor/examples/slash-menu/index.ts | 1 + .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 11 + .../editor/ui/slash-menu/slash-menu-item.tsx | 23 + .../editor/ui/slash-menu/slash-menu.tsx | 102 +++ react-slash-menu/src/main.tsx | 10 + react-slash-menu/tsconfig.app.json | 28 + react-slash-menu/tsconfig.json | 7 + react-slash-menu/tsconfig.node.json | 26 + react-slash-menu/vite.config.ts | 8 + react-strike/.gitignore | 4 + react-strike/README.md | 15 + react-strike/index.html | 12 + react-strike/package.json | 28 + react-strike/src/App.tsx | 5 + react-strike/src/app.css | 12 + .../editor/examples/strike/editor.tsx | 39 + .../editor/examples/strike/extension.ts | 17 + .../editor/examples/strike/index.ts | 1 + .../editor/examples/strike/toolbar.tsx | 34 + .../editor/sample/sample-doc-strike.ts | 30 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + react-strike/src/main.tsx | 10 + react-strike/tsconfig.app.json | 28 + react-strike/tsconfig.json | 7 + react-strike/tsconfig.node.json | 26 + react-strike/vite.config.ts | 8 + react-sub-sup/.gitignore | 4 + react-sub-sup/README.md | 15 + react-sub-sup/index.html | 12 + react-sub-sup/package.json | 28 + react-sub-sup/src/App.tsx | 5 + react-sub-sup/src/app.css | 12 + .../editor/examples/sub-sup/editor.tsx | 39 + .../editor/examples/sub-sup/extension.ts | 32 + .../editor/examples/sub-sup/index.ts | 1 + .../editor/examples/sub-sup/toolbar.tsx | 46 ++ .../editor/sample/sample-doc-sub-sup.ts | 42 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + react-sub-sup/src/main.tsx | 10 + react-sub-sup/tsconfig.app.json | 28 + react-sub-sup/tsconfig.json | 7 + react-sub-sup/tsconfig.node.json | 26 + react-sub-sup/vite.config.ts | 8 + react-table/.gitignore | 4 + react-table/README.md | 15 + react-table/index.html | 12 + react-table/package.json | 28 + react-table/src/App.tsx | 5 + react-table/src/app.css | 12 + .../editor/examples/table/editor.tsx | 39 + .../editor/examples/table/extension.ts | 20 + .../components/editor/examples/table/index.ts | 1 + .../editor/sample/sample-doc-table.ts | 174 +++++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 188 +++++ react-table/src/main.tsx | 10 + react-table/tsconfig.app.json | 28 + react-table/tsconfig.json | 7 + react-table/tsconfig.node.json | 26 + react-table/vite.config.ts | 8 + react-text-align/.gitignore | 4 + react-text-align/README.md | 15 + react-text-align/index.html | 12 + react-text-align/package.json | 28 + react-text-align/src/App.tsx | 5 + react-text-align/src/app.css | 12 + .../editor/examples/text-align/editor.tsx | 39 + .../editor/examples/text-align/extension.ts | 12 + .../editor/examples/text-align/index.ts | 1 + .../editor/examples/text-align/toolbar.tsx | 80 ++ .../editor/sample/sample-doc-text-align.ts | 56 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + react-text-align/src/main.tsx | 10 + react-text-align/tsconfig.app.json | 28 + react-text-align/tsconfig.json | 7 + react-text-align/tsconfig.node.json | 26 + react-text-align/vite.config.ts | 8 + react-text-color/.gitignore | 4 + react-text-color/README.md | 15 + react-text-color/index.html | 12 + react-text-color/package.json | 28 + react-text-color/src/App.tsx | 5 + react-text-color/src/app.css | 12 + .../editor/examples/text-color/editor.tsx | 39 + .../editor/examples/text-color/extension.ts | 14 + .../editor/examples/text-color/index.ts | 1 + .../examples/text-color/inline-menu.tsx | 147 ++++ .../editor/sample/sample-doc-text-color.ts | 120 +++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + react-text-color/src/main.tsx | 10 + react-text-color/tsconfig.app.json | 28 + react-text-color/tsconfig.json | 7 + react-text-color/tsconfig.node.json | 26 + react-text-color/vite.config.ts | 8 + react-toolbar/.gitignore | 4 + react-toolbar/README.md | 15 + react-toolbar/index.html | 12 + react-toolbar/package.json | 28 + react-toolbar/src/App.tsx | 5 + react-toolbar/src/app.css | 12 + .../editor/examples/toolbar/editor.tsx | 34 + .../editor/examples/toolbar/extension.ts | 8 + .../editor/examples/toolbar/index.ts | 1 + .../editor/sample/sample-uploader.ts | 54 ++ .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-toolbar/src/main.tsx | 10 + react-toolbar/tsconfig.app.json | 28 + react-toolbar/tsconfig.json | 7 + react-toolbar/tsconfig.node.json | 26 + react-toolbar/vite.config.ts | 8 + react-tweet/.gitignore | 4 + react-tweet/README.md | 15 + react-tweet/index.html | 12 + react-tweet/package.json | 29 + react-tweet/src/App.tsx | 5 + react-tweet/src/app.css | 12 + .../editor/examples/tweet/editor.tsx | 53 ++ .../editor/examples/tweet/extension.ts | 43 ++ .../components/editor/examples/tweet/index.ts | 1 + .../editor/examples/tweet/method-select.tsx | 42 ++ .../editor/examples/tweet/tweet-view.tsx | 27 + .../editor/sample/sample-doc-tweet.ts | 22 + react-tweet/src/main.tsx | 10 + react-tweet/tsconfig.app.json | 28 + react-tweet/tsconfig.json | 7 + react-tweet/tsconfig.node.json | 26 + react-tweet/vite.config.ts | 8 + react-typography/.gitignore | 4 + react-typography/README.md | 15 + react-typography/index.html | 12 + react-typography/package.json | 29 + react-typography/src/App.tsx | 5 + react-typography/src/app.css | 12 + .../editor/examples/typography/editor.tsx | 41 ++ .../editor/examples/typography/extension.ts | 17 + .../editor/examples/typography/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-typography.ts | 693 ++++++++++++++++++ .../editor/ui/block-handle/block-handle.tsx | 33 + .../editor/ui/block-handle/index.ts | 1 + .../ui/drop-indicator/drop-indicator.tsx | 7 + .../editor/ui/drop-indicator/index.ts | 1 + react-typography/src/main.tsx | 10 + react-typography/tsconfig.app.json | 28 + react-typography/tsconfig.json | 7 + react-typography/tsconfig.node.json | 26 + react-typography/vite.config.ts | 8 + react-underline/.gitignore | 4 + react-underline/README.md | 15 + react-underline/index.html | 12 + react-underline/package.json | 28 + react-underline/src/App.tsx | 5 + react-underline/src/app.css | 12 + .../editor/examples/underline/editor.tsx | 39 + .../editor/examples/underline/extension.ts | 17 + .../editor/examples/underline/index.ts | 1 + .../editor/sample/sample-doc-underline.ts | 30 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-underline/src/main.tsx | 10 + react-underline/tsconfig.app.json | 28 + react-underline/tsconfig.json | 7 + react-underline/tsconfig.node.json | 26 + react-underline/vite.config.ts | 8 + react-unmount/.gitignore | 4 + react-unmount/README.md | 15 + react-unmount/index.html | 12 + react-unmount/package.json | 28 + react-unmount/src/App.tsx | 5 + react-unmount/src/app.css | 12 + .../examples/unmount/editor-component.tsx | 34 + .../editor/examples/unmount/editor.tsx | 46 ++ .../examples/unmount/extension-component.tsx | 16 + .../editor/examples/unmount/index.ts | 1 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 221 ++++++ react-unmount/src/main.tsx | 10 + react-unmount/tsconfig.app.json | 28 + react-unmount/tsconfig.json | 7 + react-unmount/tsconfig.node.json | 26 + react-unmount/vite.config.ts | 8 + react-user-menu-dynamic/.gitignore | 4 + react-user-menu-dynamic/README.md | 15 + react-user-menu-dynamic/index.html | 12 + react-user-menu-dynamic/package.json | 28 + react-user-menu-dynamic/src/App.tsx | 5 + react-user-menu-dynamic/src/app.css | 12 + .../examples/user-menu-dynamic/editor.tsx | 32 + .../examples/user-menu-dynamic/extension.ts | 16 + .../examples/user-menu-dynamic/index.ts | 1 + .../user-menu-dynamic/use-user-query.ts | 40 + .../user-menu-dynamic/user-menu-dynamic.tsx | 23 + .../editor/sample/sample-query-users.ts | 40 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 64 ++ react-user-menu-dynamic/src/main.tsx | 10 + react-user-menu-dynamic/tsconfig.app.json | 28 + react-user-menu-dynamic/tsconfig.json | 7 + react-user-menu-dynamic/tsconfig.node.json | 26 + react-user-menu-dynamic/vite.config.ts | 8 + react-user-menu/.gitignore | 4 + react-user-menu/README.md | 15 + react-user-menu/index.html | 12 + react-user-menu/package.json | 28 + react-user-menu/src/App.tsx | 5 + react-user-menu/src/app.css | 12 + .../editor/examples/user-menu/editor.tsx | 37 + .../editor/examples/user-menu/extension.ts | 16 + .../editor/examples/user-menu/index.ts | 1 + .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.tsx | 54 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 64 ++ react-user-menu/src/main.tsx | 10 + react-user-menu/tsconfig.app.json | 28 + react-user-menu/tsconfig.json | 7 + react-user-menu/tsconfig.node.json | 26 + react-user-menu/vite.config.ts | 8 + react-word-counter/.gitignore | 4 + react-word-counter/README.md | 15 + react-word-counter/index.html | 12 + react-word-counter/package.json | 28 + react-word-counter/src/App.tsx | 5 + react-word-counter/src/app.css | 12 + .../editor/examples/word-counter/editor.tsx | 42 ++ .../editor/examples/word-counter/extension.ts | 8 + .../editor/examples/word-counter/index.ts | 1 + .../editor/sample/sample-doc-word-counter.ts | 16 + .../editor/ui/word-counter/index.ts | 1 + .../editor/ui/word-counter/word-counter.tsx | 24 + react-word-counter/src/main.tsx | 10 + react-word-counter/tsconfig.app.json | 28 + react-word-counter/tsconfig.json | 7 + react-word-counter/tsconfig.node.json | 26 + react-word-counter/vite.config.ts | 8 + react-yjs/.gitignore | 4 + react-yjs/README.md | 15 + react-yjs/index.html | 12 + react-yjs/package.json | 31 + react-yjs/src/App.tsx | 5 + react-yjs/src/app.css | 12 + .../editor/examples/yjs/editor-component.tsx | 43 ++ .../components/editor/examples/yjs/editor.tsx | 18 + .../editor/examples/yjs/extension.ts | 48 ++ .../components/editor/examples/yjs/index.ts | 1 + .../components/editor/ui/button/button.tsx | 46 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 145 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 365 +++++++++ react-yjs/src/main.tsx | 10 + react-yjs/tsconfig.app.json | 28 + react-yjs/tsconfig.json | 7 + react-yjs/tsconfig.node.json | 26 + react-yjs/vite.config.ts | 8 + solid-block-handle/.gitignore | 4 + solid-block-handle/README.md | 15 + solid-block-handle/index.html | 12 + solid-block-handle/package.json | 25 + solid-block-handle/src/App.tsx | 5 + solid-block-handle/src/app.css | 12 + .../editor/examples/block-handle/editor.tsx | 37 + .../editor/examples/block-handle/extension.ts | 10 + .../editor/examples/block-handle/index.ts | 1 + .../editor/sample/sample-doc-block-handle.ts | 323 ++++++++ .../editor/ui/block-handle/block-handle.tsx | 32 + .../editor/ui/block-handle/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 36 + .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.tsx | 6 + .../editor/ui/drop-indicator/index.ts | 1 + solid-block-handle/src/index.tsx | 8 + solid-block-handle/tsconfig.app.json | 29 + solid-block-handle/tsconfig.json | 7 + solid-block-handle/tsconfig.node.json | 26 + solid-block-handle/vite.config.ts | 7 + solid-blockquote/.gitignore | 4 + solid-blockquote/README.md | 15 + solid-blockquote/index.html | 12 + solid-blockquote/package.json | 25 + solid-blockquote/src/App.tsx | 5 + solid-blockquote/src/app.css | 12 + .../editor/examples/blockquote/editor.tsx | 29 + .../editor/examples/blockquote/extension.ts | 17 + .../editor/examples/blockquote/index.ts | 1 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-blockquote/src/index.tsx | 8 + solid-blockquote/tsconfig.app.json | 29 + solid-blockquote/tsconfig.json | 7 + solid-blockquote/tsconfig.node.json | 26 + solid-blockquote/vite.config.ts | 7 + solid-bold/.gitignore | 4 + solid-bold/README.md | 15 + solid-bold/index.html | 12 + solid-bold/package.json | 25 + solid-bold/src/App.tsx | 5 + solid-bold/src/app.css | 12 + .../editor/examples/bold/editor.tsx | 35 + .../editor/examples/bold/extension.ts | 17 + .../components/editor/examples/bold/index.ts | 1 + .../editor/sample/sample-doc-bold.ts | 44 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-bold/src/index.tsx | 8 + solid-bold/tsconfig.app.json | 29 + solid-bold/tsconfig.json | 7 + solid-bold/tsconfig.node.json | 26 + solid-bold/vite.config.ts | 7 + solid-change-tracking/.gitignore | 4 + solid-change-tracking/README.md | 15 + solid-change-tracking/index.html | 12 + solid-change-tracking/package.json | 25 + solid-change-tracking/src/App.tsx | 5 + solid-change-tracking/src/app.css | 12 + .../examples/change-tracking/editor-diff.tsx | 28 + .../examples/change-tracking/editor-main.tsx | 38 + .../examples/change-tracking/editor.tsx | 82 +++ .../editor/examples/change-tracking/index.ts | 1 + solid-change-tracking/src/index.tsx | 8 + solid-change-tracking/tsconfig.app.json | 29 + solid-change-tracking/tsconfig.json | 7 + solid-change-tracking/tsconfig.node.json | 26 + solid-change-tracking/vite.config.ts | 7 + solid-code-block-themes/.gitignore | 4 + solid-code-block-themes/README.md | 15 + solid-code-block-themes/index.html | 12 + solid-code-block-themes/package.json | 25 + solid-code-block-themes/src/App.tsx | 5 + solid-code-block-themes/src/app.css | 12 + .../examples/code-block-themes/editor.tsx | 35 + .../examples/code-block-themes/extension.ts | 10 + .../examples/code-block-themes/index.ts | 1 + .../code-block-themes/theme-selector.tsx | 31 + .../examples/code-block-themes/toolbar.tsx | 11 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../ui/code-block-view/code-block-view.tsx | 36 + .../editor/ui/code-block-view/index.ts | 15 + solid-code-block-themes/src/index.tsx | 8 + solid-code-block-themes/tsconfig.app.json | 29 + solid-code-block-themes/tsconfig.json | 7 + solid-code-block-themes/tsconfig.node.json | 26 + solid-code-block-themes/vite.config.ts | 7 + solid-code-block/.gitignore | 4 + solid-code-block/README.md | 15 + solid-code-block/index.html | 12 + solid-code-block/package.json | 25 + solid-code-block/src/App.tsx | 5 + solid-code-block/src/app.css | 12 + .../editor/examples/code-block/editor.tsx | 35 + .../editor/examples/code-block/extension.ts | 24 + .../editor/examples/code-block/index.ts | 1 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 36 + .../editor/ui/code-block-view/index.ts | 15 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-code-block/src/index.tsx | 8 + solid-code-block/tsconfig.app.json | 29 + solid-code-block/tsconfig.json | 7 + solid-code-block/tsconfig.node.json | 26 + solid-code-block/vite.config.ts | 7 + solid-code/.gitignore | 4 + solid-code/README.md | 15 + solid-code/index.html | 12 + solid-code/package.json | 25 + solid-code/src/App.tsx | 5 + solid-code/src/app.css | 12 + .../editor/examples/code/editor.tsx | 35 + .../editor/examples/code/extension.ts | 17 + .../components/editor/examples/code/index.ts | 1 + .../editor/sample/sample-doc-code.ts | 30 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-code/src/index.tsx | 8 + solid-code/tsconfig.app.json | 29 + solid-code/tsconfig.json | 7 + solid-code/tsconfig.node.json | 26 + solid-code/vite.config.ts | 7 + solid-drop-cursor/.gitignore | 4 + solid-drop-cursor/README.md | 15 + solid-drop-cursor/index.html | 12 + solid-drop-cursor/package.json | 25 + solid-drop-cursor/src/App.tsx | 5 + solid-drop-cursor/src/app.css | 12 + .../editor/examples/drop-cursor/editor.tsx | 33 + .../editor/examples/drop-cursor/extension.ts | 23 + .../editor/examples/drop-cursor/index.ts | 1 + .../editor/sample/sample-doc-drop-cursor.ts | 40 + solid-drop-cursor/src/index.tsx | 8 + solid-drop-cursor/tsconfig.app.json | 29 + solid-drop-cursor/tsconfig.json | 7 + solid-drop-cursor/tsconfig.node.json | 26 + solid-drop-cursor/vite.config.ts | 7 + solid-emoji-rules/.gitignore | 4 + solid-emoji-rules/README.md | 15 + solid-emoji-rules/index.html | 12 + solid-emoji-rules/package.json | 25 + solid-emoji-rules/src/App.tsx | 5 + solid-emoji-rules/src/app.css | 12 + .../editor/examples/emoji-rules/editor.tsx | 26 + .../editor/examples/emoji-rules/emoji.ts | 15 + .../editor/examples/emoji-rules/extension.ts | 15 + .../editor/examples/emoji-rules/index.ts | 1 + solid-emoji-rules/src/index.tsx | 8 + solid-emoji-rules/tsconfig.app.json | 29 + solid-emoji-rules/tsconfig.json | 7 + solid-emoji-rules/tsconfig.node.json | 26 + solid-emoji-rules/vite.config.ts | 7 + solid-full/.gitignore | 4 + solid-full/README.md | 15 + solid-full/index.html | 12 + solid-full/package.json | 26 + solid-full/src/App.tsx | 5 + solid-full/src/app.css | 12 + .../editor/examples/full/editor.tsx | 52 ++ .../editor/examples/full/extension.ts | 34 + .../components/editor/examples/full/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-full.ts | 442 +++++++++++ .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/sample/sample-user-data.ts | 54 ++ .../editor/ui/block-handle/block-handle.tsx | 32 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.tsx | 36 + .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.tsx | 6 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../editor/ui/image-view/image-view.tsx | 90 +++ .../components/editor/ui/image-view/index.ts | 14 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 233 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 10 + .../editor/ui/slash-menu/slash-menu-item.tsx | 22 + .../editor/ui/slash-menu/slash-menu.tsx | 101 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 187 +++++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.tsx | 54 ++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 64 ++ solid-full/src/index.tsx | 8 + solid-full/tsconfig.app.json | 29 + solid-full/tsconfig.json | 7 + solid-full/tsconfig.node.json | 26 + solid-full/vite.config.ts | 7 + solid-gap-cursor/.gitignore | 4 + solid-gap-cursor/README.md | 15 + solid-gap-cursor/index.html | 12 + solid-gap-cursor/package.json | 25 + solid-gap-cursor/src/App.tsx | 5 + solid-gap-cursor/src/app.css | 12 + .../editor/examples/gap-cursor/editor.tsx | 33 + .../editor/examples/gap-cursor/extension.ts | 19 + .../editor/examples/gap-cursor/index.ts | 1 + .../editor/sample/sample-doc-gap-cursor.ts | 28 + solid-gap-cursor/src/index.tsx | 8 + solid-gap-cursor/tsconfig.app.json | 29 + solid-gap-cursor/tsconfig.json | 7 + solid-gap-cursor/tsconfig.node.json | 26 + solid-gap-cursor/vite.config.ts | 7 + solid-hard-break/.gitignore | 4 + solid-hard-break/README.md | 15 + solid-hard-break/index.html | 12 + solid-hard-break/package.json | 25 + solid-hard-break/src/App.tsx | 5 + solid-hard-break/src/app.css | 12 + .../editor/examples/hard-break/editor.tsx | 35 + .../editor/examples/hard-break/extension.ts | 17 + .../editor/examples/hard-break/index.ts | 1 + .../editor/examples/hard-break/toolbar.tsx | 32 + .../editor/sample/sample-doc-hard-break.ts | 68 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + solid-hard-break/src/index.tsx | 8 + solid-hard-break/tsconfig.app.json | 29 + solid-hard-break/tsconfig.json | 7 + solid-hard-break/tsconfig.node.json | 26 + solid-hard-break/vite.config.ts | 7 + solid-heading/.gitignore | 4 + solid-heading/README.md | 15 + solid-heading/index.html | 12 + solid-heading/package.json | 25 + solid-heading/src/App.tsx | 5 + solid-heading/src/app.css | 12 + .../editor/examples/heading/editor.tsx | 35 + .../editor/examples/heading/extension.ts | 17 + .../editor/examples/heading/index.ts | 1 + .../editor/sample/sample-doc-heading.ts | 23 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-heading/src/index.tsx | 8 + solid-heading/tsconfig.app.json | 29 + solid-heading/tsconfig.json | 7 + solid-heading/tsconfig.node.json | 26 + solid-heading/vite.config.ts | 7 + solid-highlight/.gitignore | 4 + solid-highlight/README.md | 15 + solid-highlight/index.html | 12 + solid-highlight/package.json | 25 + solid-highlight/src/App.tsx | 5 + solid-highlight/src/app.css | 12 + .../editor/examples/highlight/editor.tsx | 35 + .../editor/examples/highlight/extension.ts | 17 + .../editor/examples/highlight/index.ts | 1 + .../editor/examples/highlight/toolbar.tsx | 33 + .../editor/sample/sample-doc-highlight.ts | 30 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + solid-highlight/src/index.tsx | 8 + solid-highlight/tsconfig.app.json | 29 + solid-highlight/tsconfig.json | 7 + solid-highlight/tsconfig.node.json | 26 + solid-highlight/vite.config.ts | 7 + solid-horizontal-rule/.gitignore | 4 + solid-horizontal-rule/README.md | 15 + solid-horizontal-rule/index.html | 12 + solid-horizontal-rule/package.json | 25 + solid-horizontal-rule/src/App.tsx | 5 + solid-horizontal-rule/src/app.css | 12 + .../examples/horizontal-rule/editor.tsx | 29 + .../examples/horizontal-rule/extension.ts | 17 + .../editor/examples/horizontal-rule/index.ts | 1 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-horizontal-rule/src/index.tsx | 8 + solid-horizontal-rule/tsconfig.app.json | 29 + solid-horizontal-rule/tsconfig.json | 7 + solid-horizontal-rule/tsconfig.node.json | 26 + solid-horizontal-rule/vite.config.ts | 7 + solid-image-view/.gitignore | 4 + solid-image-view/README.md | 15 + solid-image-view/index.html | 12 + solid-image-view/package.json | 25 + solid-image-view/src/App.tsx | 5 + solid-image-view/src/app.css | 12 + .../editor/examples/image-view/editor.tsx | 33 + .../editor/examples/image-view/extension.ts | 18 + .../editor/examples/image-view/index.ts | 1 + .../editor/sample/sample-doc-image.ts | 32 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/image-view/image-view.tsx | 90 +++ .../components/editor/ui/image-view/index.ts | 14 + solid-image-view/src/index.tsx | 8 + solid-image-view/tsconfig.app.json | 29 + solid-image-view/tsconfig.json | 7 + solid-image-view/tsconfig.node.json | 26 + solid-image-view/vite.config.ts | 7 + solid-inline-menu/.gitignore | 4 + solid-inline-menu/README.md | 15 + solid-inline-menu/index.html | 12 + solid-inline-menu/package.json | 25 + solid-inline-menu/src/App.tsx | 5 + solid-inline-menu/src/app.css | 12 + .../editor/examples/inline-menu/editor.tsx | 35 + .../editor/examples/inline-menu/extension.ts | 7 + .../editor/examples/inline-menu/index.ts | 1 + .../editor/sample/sample-doc-inline-menu.ts | 33 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 233 ++++++ solid-inline-menu/src/index.tsx | 8 + solid-inline-menu/tsconfig.app.json | 29 + solid-inline-menu/tsconfig.json | 7 + solid-inline-menu/tsconfig.node.json | 26 + solid-inline-menu/vite.config.ts | 7 + solid-italic/.gitignore | 4 + solid-italic/README.md | 15 + solid-italic/index.html | 12 + solid-italic/package.json | 25 + solid-italic/src/App.tsx | 5 + solid-italic/src/app.css | 12 + .../editor/examples/italic/editor.tsx | 35 + .../editor/examples/italic/extension.ts | 17 + .../editor/examples/italic/index.ts | 1 + .../editor/sample/sample-doc-italic.ts | 44 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-italic/src/index.tsx | 8 + solid-italic/tsconfig.app.json | 29 + solid-italic/tsconfig.json | 7 + solid-italic/tsconfig.node.json | 26 + solid-italic/vite.config.ts | 7 + solid-katex/.gitignore | 4 + solid-katex/README.md | 15 + solid-katex/index.html | 12 + solid-katex/package.json | 26 + solid-katex/src/App.tsx | 5 + solid-katex/src/app.css | 12 + .../editor/examples/katex/editor.tsx | 33 + .../editor/examples/katex/extension.ts | 17 + .../components/editor/examples/katex/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-tex.ts | 60 ++ solid-katex/src/index.tsx | 8 + solid-katex/tsconfig.app.json | 29 + solid-katex/tsconfig.json | 7 + solid-katex/tsconfig.node.json | 26 + solid-katex/vite.config.ts | 7 + solid-keymap/.gitignore | 4 + solid-keymap/README.md | 15 + solid-keymap/index.html | 12 + solid-keymap/package.json | 25 + solid-keymap/src/App.tsx | 5 + solid-keymap/src/app.css | 12 + .../editor/examples/keymap/editor.tsx | 51 ++ .../editor/examples/keymap/extension.ts | 8 + .../editor/examples/keymap/index.ts | 1 + .../editor/examples/keymap/toolbar.tsx | 31 + .../examples/keymap/use-submit-keymap.ts | 20 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + solid-keymap/src/index.tsx | 8 + solid-keymap/tsconfig.app.json | 29 + solid-keymap/tsconfig.json | 7 + solid-keymap/tsconfig.node.json | 26 + solid-keymap/vite.config.ts | 7 + solid-link-mark-view/.gitignore | 4 + solid-link-mark-view/README.md | 15 + solid-link-mark-view/index.html | 12 + solid-link-mark-view/package.json | 25 + solid-link-mark-view/src/App.tsx | 5 + solid-link-mark-view/src/app.css | 12 + .../editor/examples/link-mark-view/editor.tsx | 33 + .../examples/link-mark-view/extension.ts | 17 + .../editor/examples/link-mark-view/index.ts | 1 + .../examples/link-mark-view/link-view.tsx | 46 ++ .../sample/sample-doc-link-mark-view.ts | 30 + solid-link-mark-view/src/index.tsx | 8 + solid-link-mark-view/tsconfig.app.json | 29 + solid-link-mark-view/tsconfig.json | 7 + solid-link-mark-view/tsconfig.node.json | 26 + solid-link-mark-view/vite.config.ts | 7 + solid-link/.gitignore | 4 + solid-link/README.md | 15 + solid-link/index.html | 12 + solid-link/package.json | 25 + solid-link/src/App.tsx | 5 + solid-link/src/app.css | 12 + .../editor/examples/link/editor.tsx | 35 + .../editor/examples/link/extension.ts | 17 + .../components/editor/examples/link/index.ts | 1 + .../editor/sample/sample-doc-link.ts | 30 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 233 ++++++ solid-link/src/index.tsx | 8 + solid-link/tsconfig.app.json | 29 + solid-link/tsconfig.json | 7 + solid-link/tsconfig.node.json | 26 + solid-link/vite.config.ts | 7 + solid-list-custom-checkbox/.gitignore | 4 + solid-list-custom-checkbox/README.md | 15 + solid-list-custom-checkbox/index.html | 12 + solid-list-custom-checkbox/package.json | 25 + solid-list-custom-checkbox/src/App.tsx | 5 + solid-list-custom-checkbox/src/app.css | 12 + .../list-custom-checkbox/custom-list.css | 75 ++ .../examples/list-custom-checkbox/editor.tsx | 42 ++ .../list-custom-checkbox/extension.ts | 8 + .../examples/list-custom-checkbox/index.ts | 1 + .../sample/sample-doc-list-custom-checkbox.ts | 38 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-list-custom-checkbox/src/index.tsx | 8 + solid-list-custom-checkbox/tsconfig.app.json | 29 + solid-list-custom-checkbox/tsconfig.json | 7 + solid-list-custom-checkbox/tsconfig.node.json | 26 + solid-list-custom-checkbox/vite.config.ts | 7 + solid-list/.gitignore | 4 + solid-list/README.md | 15 + solid-list/index.html | 12 + solid-list/package.json | 25 + solid-list/src/App.tsx | 5 + solid-list/src/app.css | 12 + .../editor/examples/list/editor.tsx | 35 + .../editor/examples/list/extension.ts | 17 + .../components/editor/examples/list/index.ts | 1 + .../editor/sample/sample-doc-list.ts | 47 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-list/src/index.tsx | 8 + solid-list/tsconfig.app.json | 29 + solid-list/tsconfig.json | 7 + solid-list/tsconfig.node.json | 26 + solid-list/vite.config.ts | 7 + solid-loro/.gitignore | 4 + solid-loro/README.md | 15 + solid-loro/index.html | 12 + solid-loro/package.json | 28 + solid-loro/src/App.tsx | 5 + solid-loro/src/app.css | 12 + .../editor/examples/loro/editor-component.tsx | 34 + .../editor/examples/loro/editor.tsx | 56 ++ .../editor/examples/loro/extension.ts | 47 ++ .../components/editor/examples/loro/index.ts | 1 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-loro/src/index.tsx | 8 + solid-loro/tsconfig.app.json | 29 + solid-loro/tsconfig.json | 7 + solid-loro/tsconfig.node.json | 26 + solid-loro/vite.config.ts | 8 + solid-mark-rule/.gitignore | 4 + solid-mark-rule/README.md | 15 + solid-mark-rule/index.html | 12 + solid-mark-rule/package.json | 25 + solid-mark-rule/src/App.tsx | 5 + solid-mark-rule/src/app.css | 12 + .../editor/examples/mark-rule/editor.tsx | 26 + .../editor/examples/mark-rule/extension.ts | 32 + .../editor/examples/mark-rule/index.ts | 1 + .../editor/examples/mark-rule/issue-link.ts | 32 + solid-mark-rule/src/index.tsx | 8 + solid-mark-rule/tsconfig.app.json | 29 + solid-mark-rule/tsconfig.json | 7 + solid-mark-rule/tsconfig.node.json | 26 + solid-mark-rule/vite.config.ts | 7 + solid-minimal/.gitignore | 4 + solid-minimal/README.md | 15 + solid-minimal/index.html | 12 + solid-minimal/package.json | 25 + solid-minimal/src/App.tsx | 5 + solid-minimal/src/app.css | 12 + .../editor/examples/minimal/editor.tsx | 18 + .../editor/examples/minimal/index.ts | 1 + solid-minimal/src/index.tsx | 8 + solid-minimal/tsconfig.app.json | 29 + solid-minimal/tsconfig.json | 7 + solid-minimal/tsconfig.node.json | 26 + solid-minimal/vite.config.ts | 7 + solid-placeholder/.gitignore | 4 + solid-placeholder/README.md | 15 + solid-placeholder/index.html | 12 + solid-placeholder/package.json | 25 + solid-placeholder/src/App.tsx | 5 + solid-placeholder/src/app.css | 12 + .../editor/examples/placeholder/editor.tsx | 37 + .../editor/examples/placeholder/extension.ts | 12 + .../editor/examples/placeholder/index.ts | 1 + solid-placeholder/src/index.tsx | 8 + solid-placeholder/tsconfig.app.json | 29 + solid-placeholder/tsconfig.json | 7 + solid-placeholder/tsconfig.node.json | 26 + solid-placeholder/vite.config.ts | 7 + solid-readonly/.gitignore | 4 + solid-readonly/README.md | 15 + solid-readonly/index.html | 12 + solid-readonly/package.json | 25 + solid-readonly/src/App.tsx | 5 + solid-readonly/src/app.css | 12 + .../editor/examples/readonly/editor.tsx | 35 + .../editor/examples/readonly/extension.ts | 7 + .../editor/examples/readonly/index.ts | 1 + .../editor/examples/readonly/toolbar.tsx | 21 + .../editor/examples/readonly/use-readonly.ts | 14 + .../editor/sample/sample-doc-readonly.ts | 16 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + solid-readonly/src/index.tsx | 8 + solid-readonly/tsconfig.app.json | 29 + solid-readonly/tsconfig.json | 7 + solid-readonly/tsconfig.node.json | 26 + solid-readonly/vite.config.ts | 7 + solid-rtl/.gitignore | 4 + solid-rtl/README.md | 15 + solid-rtl/index.html | 12 + solid-rtl/package.json | 25 + solid-rtl/src/App.tsx | 5 + solid-rtl/src/app.css | 12 + .../components/editor/examples/rtl/editor.tsx | 48 ++ .../components/editor/examples/rtl/index.ts | 1 + .../editor/sample/sample-doc-rtl.ts | 187 +++++ .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/block-handle/block-handle.tsx | 32 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/drop-indicator/drop-indicator.tsx | 6 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 233 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 10 + .../editor/ui/slash-menu/slash-menu-item.tsx | 22 + .../editor/ui/slash-menu/slash-menu.tsx | 101 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 187 +++++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-rtl/src/index.tsx | 8 + solid-rtl/tsconfig.app.json | 29 + solid-rtl/tsconfig.json | 7 + solid-rtl/tsconfig.node.json | 26 + solid-rtl/vite.config.ts | 7 + solid-save-html/.gitignore | 4 + solid-save-html/README.md | 15 + solid-save-html/index.html | 12 + solid-save-html/package.json | 25 + solid-save-html/src/App.tsx | 5 + solid-save-html/src/app.css | 12 + .../editor/examples/save-html/editor.tsx | 66 ++ .../editor/examples/save-html/index.ts | 1 + solid-save-html/src/index.tsx | 8 + solid-save-html/tsconfig.app.json | 29 + solid-save-html/tsconfig.json | 7 + solid-save-html/tsconfig.node.json | 26 + solid-save-html/vite.config.ts | 7 + solid-save-json/.gitignore | 4 + solid-save-json/README.md | 15 + solid-save-json/index.html | 12 + solid-save-json/package.json | 25 + solid-save-json/src/App.tsx | 5 + solid-save-json/src/app.css | 12 + .../editor/examples/save-json/editor.tsx | 66 ++ .../editor/examples/save-json/index.ts | 1 + solid-save-json/src/index.tsx | 8 + solid-save-json/tsconfig.app.json | 29 + solid-save-json/tsconfig.json | 7 + solid-save-json/tsconfig.node.json | 26 + solid-save-json/vite.config.ts | 7 + solid-save-markdown/.gitignore | 4 + solid-save-markdown/README.md | 15 + solid-save-markdown/index.html | 12 + solid-save-markdown/package.json | 32 + solid-save-markdown/src/App.tsx | 5 + solid-save-markdown/src/app.css | 12 + .../editor/examples/save-markdown/editor.tsx | 70 ++ .../editor/examples/save-markdown/index.ts | 1 + .../editor/examples/save-markdown/markdown.ts | 26 + solid-save-markdown/src/index.tsx | 8 + solid-save-markdown/tsconfig.app.json | 29 + solid-save-markdown/tsconfig.json | 7 + solid-save-markdown/tsconfig.node.json | 26 + solid-save-markdown/vite.config.ts | 7 + solid-search/.gitignore | 4 + solid-search/README.md | 15 + solid-search/index.html | 12 + solid-search/package.json | 25 + solid-search/src/App.tsx | 5 + solid-search/src/app.css | 12 + .../editor/examples/search/editor.tsx | 39 + .../editor/examples/search/extension.ts | 9 + .../editor/examples/search/index.ts | 1 + .../editor/sample/sample-doc-search.ts | 79 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../src/components/editor/ui/search/index.ts | 1 + .../components/editor/ui/search/search.tsx | 170 +++++ solid-search/src/index.tsx | 8 + solid-search/tsconfig.app.json | 29 + solid-search/tsconfig.json | 7 + solid-search/tsconfig.node.json | 26 + solid-search/vite.config.ts | 7 + solid-slash-menu/.gitignore | 4 + solid-slash-menu/README.md | 15 + solid-slash-menu/index.html | 12 + solid-slash-menu/package.json | 25 + solid-slash-menu/src/App.tsx | 5 + solid-slash-menu/src/app.css | 12 + .../editor/examples/slash-menu/editor.tsx | 29 + .../editor/examples/slash-menu/extension.ts | 12 + .../editor/examples/slash-menu/index.ts | 1 + .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.tsx | 10 + .../editor/ui/slash-menu/slash-menu-item.tsx | 22 + .../editor/ui/slash-menu/slash-menu.tsx | 101 +++ solid-slash-menu/src/index.tsx | 8 + solid-slash-menu/tsconfig.app.json | 29 + solid-slash-menu/tsconfig.json | 7 + solid-slash-menu/tsconfig.node.json | 26 + solid-slash-menu/vite.config.ts | 7 + solid-strike/.gitignore | 4 + solid-strike/README.md | 15 + solid-strike/index.html | 12 + solid-strike/package.json | 25 + solid-strike/src/App.tsx | 5 + solid-strike/src/app.css | 12 + .../editor/examples/strike/editor.tsx | 35 + .../editor/examples/strike/extension.ts | 17 + .../editor/examples/strike/index.ts | 1 + .../editor/examples/strike/toolbar.tsx | 33 + .../editor/sample/sample-doc-strike.ts | 30 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + solid-strike/src/index.tsx | 8 + solid-strike/tsconfig.app.json | 29 + solid-strike/tsconfig.json | 7 + solid-strike/tsconfig.node.json | 26 + solid-strike/vite.config.ts | 7 + solid-sub-sup/.gitignore | 4 + solid-sub-sup/README.md | 15 + solid-sub-sup/index.html | 12 + solid-sub-sup/package.json | 25 + solid-sub-sup/src/App.tsx | 5 + solid-sub-sup/src/app.css | 12 + .../editor/examples/sub-sup/editor.tsx | 35 + .../editor/examples/sub-sup/extension.ts | 32 + .../editor/examples/sub-sup/index.ts | 1 + .../editor/examples/sub-sup/toolbar.tsx | 45 ++ .../editor/sample/sample-doc-sub-sup.ts | 42 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + solid-sub-sup/src/index.tsx | 8 + solid-sub-sup/tsconfig.app.json | 29 + solid-sub-sup/tsconfig.json | 7 + solid-sub-sup/tsconfig.node.json | 26 + solid-sub-sup/vite.config.ts | 7 + solid-table/.gitignore | 4 + solid-table/README.md | 15 + solid-table/index.html | 12 + solid-table/package.json | 25 + solid-table/src/App.tsx | 5 + solid-table/src/app.css | 12 + .../editor/examples/table/editor.tsx | 35 + .../editor/examples/table/extension.ts | 20 + .../components/editor/examples/table/index.ts | 1 + .../editor/sample/sample-doc-table.ts | 174 +++++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.tsx | 187 +++++ solid-table/src/index.tsx | 8 + solid-table/tsconfig.app.json | 29 + solid-table/tsconfig.json | 7 + solid-table/tsconfig.node.json | 26 + solid-table/vite.config.ts | 7 + solid-text-align/.gitignore | 4 + solid-text-align/README.md | 15 + solid-text-align/index.html | 12 + solid-text-align/package.json | 25 + solid-text-align/src/App.tsx | 5 + solid-text-align/src/app.css | 12 + .../editor/examples/text-align/editor.tsx | 35 + .../editor/examples/text-align/extension.ts | 12 + .../editor/examples/text-align/index.ts | 1 + .../editor/examples/text-align/toolbar.tsx | 79 ++ .../editor/sample/sample-doc-text-align.ts | 56 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + solid-text-align/src/index.tsx | 8 + solid-text-align/tsconfig.app.json | 29 + solid-text-align/tsconfig.json | 7 + solid-text-align/tsconfig.node.json | 26 + solid-text-align/vite.config.ts | 7 + solid-text-color/.gitignore | 4 + solid-text-color/README.md | 15 + solid-text-color/index.html | 12 + solid-text-color/package.json | 25 + solid-text-color/src/App.tsx | 5 + solid-text-color/src/app.css | 12 + .../editor/examples/text-color/editor.tsx | 35 + .../editor/examples/text-color/extension.ts | 14 + .../editor/examples/text-color/index.ts | 1 + .../examples/text-color/inline-menu.tsx | 144 ++++ .../editor/sample/sample-doc-text-color.ts | 120 +++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + solid-text-color/src/index.tsx | 8 + solid-text-color/tsconfig.app.json | 29 + solid-text-color/tsconfig.json | 7 + solid-text-color/tsconfig.node.json | 26 + solid-text-color/vite.config.ts | 7 + solid-toolbar/.gitignore | 4 + solid-toolbar/README.md | 15 + solid-toolbar/index.html | 12 + solid-toolbar/package.json | 25 + solid-toolbar/src/App.tsx | 5 + solid-toolbar/src/app.css | 12 + .../editor/examples/toolbar/editor.tsx | 30 + .../editor/examples/toolbar/extension.ts | 8 + .../editor/examples/toolbar/index.ts | 1 + .../editor/sample/sample-uploader.ts | 54 ++ .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-toolbar/src/index.tsx | 8 + solid-toolbar/tsconfig.app.json | 29 + solid-toolbar/tsconfig.json | 7 + solid-toolbar/tsconfig.node.json | 26 + solid-toolbar/vite.config.ts | 7 + solid-typography/.gitignore | 4 + solid-typography/README.md | 15 + solid-typography/index.html | 12 + solid-typography/package.json | 26 + solid-typography/src/App.tsx | 5 + solid-typography/src/app.css | 12 + .../editor/examples/typography/editor.tsx | 37 + .../editor/examples/typography/extension.ts | 17 + .../editor/examples/typography/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-typography.ts | 693 ++++++++++++++++++ .../editor/ui/block-handle/block-handle.tsx | 32 + .../editor/ui/block-handle/index.ts | 1 + .../ui/drop-indicator/drop-indicator.tsx | 6 + .../editor/ui/drop-indicator/index.ts | 1 + solid-typography/src/index.tsx | 8 + solid-typography/tsconfig.app.json | 29 + solid-typography/tsconfig.json | 7 + solid-typography/tsconfig.node.json | 26 + solid-typography/vite.config.ts | 7 + solid-underline/.gitignore | 4 + solid-underline/README.md | 15 + solid-underline/index.html | 12 + solid-underline/package.json | 25 + solid-underline/src/App.tsx | 5 + solid-underline/src/app.css | 12 + .../editor/examples/underline/editor.tsx | 35 + .../editor/examples/underline/extension.ts | 17 + .../editor/examples/underline/index.ts | 1 + .../editor/sample/sample-doc-underline.ts | 30 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-underline/src/index.tsx | 8 + solid-underline/tsconfig.app.json | 29 + solid-underline/tsconfig.json | 7 + solid-underline/tsconfig.node.json | 26 + solid-underline/vite.config.ts | 7 + solid-unmount/.gitignore | 4 + solid-unmount/README.md | 15 + solid-unmount/index.html | 12 + solid-unmount/package.json | 25 + solid-unmount/src/App.tsx | 5 + solid-unmount/src/app.css | 12 + .../examples/unmount/editor-component.tsx | 33 + .../editor/examples/unmount/editor.tsx | 42 ++ .../examples/unmount/extension-component.tsx | 15 + .../editor/examples/unmount/index.ts | 1 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.tsx | 233 ++++++ solid-unmount/src/index.tsx | 8 + solid-unmount/tsconfig.app.json | 29 + solid-unmount/tsconfig.json | 7 + solid-unmount/tsconfig.node.json | 26 + solid-unmount/vite.config.ts | 7 + solid-user-menu-dynamic/.gitignore | 4 + solid-user-menu-dynamic/README.md | 15 + solid-user-menu-dynamic/index.html | 12 + solid-user-menu-dynamic/package.json | 25 + solid-user-menu-dynamic/src/App.tsx | 5 + solid-user-menu-dynamic/src/app.css | 12 + .../examples/user-menu-dynamic/editor.tsx | 28 + .../examples/user-menu-dynamic/extension.ts | 16 + .../examples/user-menu-dynamic/index.ts | 1 + .../user-menu-dynamic/use-user-query.ts | 42 ++ .../user-menu-dynamic/user-menu-dynamic.tsx | 21 + .../editor/sample/sample-query-users.ts | 40 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 64 ++ solid-user-menu-dynamic/src/index.tsx | 8 + solid-user-menu-dynamic/tsconfig.app.json | 29 + solid-user-menu-dynamic/tsconfig.json | 7 + solid-user-menu-dynamic/tsconfig.node.json | 26 + solid-user-menu-dynamic/vite.config.ts | 7 + solid-user-menu/.gitignore | 4 + solid-user-menu/README.md | 15 + solid-user-menu/index.html | 12 + solid-user-menu/package.json | 25 + solid-user-menu/src/App.tsx | 5 + solid-user-menu/src/app.css | 12 + .../editor/examples/user-menu/editor.tsx | 33 + .../editor/examples/user-menu/extension.ts | 16 + .../editor/examples/user-menu/index.ts | 1 + .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.tsx | 54 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.tsx | 64 ++ solid-user-menu/src/index.tsx | 8 + solid-user-menu/tsconfig.app.json | 29 + solid-user-menu/tsconfig.json | 7 + solid-user-menu/tsconfig.node.json | 26 + solid-user-menu/vite.config.ts | 7 + solid-word-counter/.gitignore | 4 + solid-word-counter/README.md | 15 + solid-word-counter/index.html | 12 + solid-word-counter/package.json | 25 + solid-word-counter/src/App.tsx | 5 + solid-word-counter/src/app.css | 12 + .../editor/examples/word-counter/editor.tsx | 35 + .../editor/examples/word-counter/extension.ts | 8 + .../editor/examples/word-counter/index.ts | 1 + .../editor/sample/sample-doc-word-counter.ts | 16 + .../editor/ui/word-counter/index.ts | 1 + .../editor/ui/word-counter/word-counter.tsx | 23 + solid-word-counter/src/index.tsx | 8 + solid-word-counter/tsconfig.app.json | 29 + solid-word-counter/tsconfig.json | 7 + solid-word-counter/tsconfig.node.json | 26 + solid-word-counter/vite.config.ts | 7 + solid-yjs/.gitignore | 4 + solid-yjs/README.md | 15 + solid-yjs/index.html | 12 + solid-yjs/package.json | 28 + solid-yjs/src/App.tsx | 5 + solid-yjs/src/app.css | 12 + .../editor/examples/yjs/editor-component.tsx | 41 ++ .../components/editor/examples/yjs/editor.tsx | 14 + .../editor/examples/yjs/extension.ts | 48 ++ .../components/editor/examples/yjs/index.ts | 1 + .../components/editor/ui/button/button.tsx | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.tsx | 137 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.tsx | 406 ++++++++++ solid-yjs/src/index.tsx | 8 + solid-yjs/tsconfig.app.json | 29 + solid-yjs/tsconfig.json | 7 + solid-yjs/tsconfig.node.json | 26 + solid-yjs/vite.config.ts | 7 + svelte-block-handle/.gitignore | 4 + svelte-block-handle/README.md | 15 + svelte-block-handle/index.html | 12 + svelte-block-handle/package.json | 28 + svelte-block-handle/src/App.svelte | 5 + svelte-block-handle/src/app.css | 12 + .../examples/block-handle/editor.svelte | 32 + .../editor/examples/block-handle/extension.ts | 10 + .../editor/examples/block-handle/index.ts | 1 + .../editor/sample/sample-doc-block-handle.ts | 323 ++++++++ .../ui/block-handle/block-handle.svelte | 28 + .../editor/ui/block-handle/index.ts | 1 + .../ui/code-block-view/code-block-view.svelte | 40 + .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.svelte | 5 + .../editor/ui/drop-indicator/index.ts | 1 + svelte-block-handle/src/main.ts | 8 + svelte-block-handle/src/vite-env.d.ts | 2 + svelte-block-handle/svelte.config.js | 7 + svelte-block-handle/tsconfig.json | 21 + svelte-block-handle/tsconfig.node.json | 9 + svelte-block-handle/vite.config.ts | 8 + svelte-blockquote/.gitignore | 4 + svelte-blockquote/README.md | 15 + svelte-blockquote/index.html | 12 + svelte-blockquote/package.json | 28 + svelte-blockquote/src/App.svelte | 5 + svelte-blockquote/src/app.css | 12 + .../editor/examples/blockquote/editor.svelte | 23 + .../editor/examples/blockquote/extension.ts | 17 + .../editor/examples/blockquote/index.ts | 1 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-blockquote/src/main.ts | 8 + svelte-blockquote/src/vite-env.d.ts | 2 + svelte-blockquote/svelte.config.js | 7 + svelte-blockquote/tsconfig.json | 21 + svelte-blockquote/tsconfig.node.json | 9 + svelte-blockquote/vite.config.ts | 8 + svelte-bold/.gitignore | 4 + svelte-bold/README.md | 15 + svelte-bold/index.html | 12 + svelte-bold/package.json | 28 + svelte-bold/src/App.svelte | 5 + svelte-bold/src/app.css | 12 + .../editor/examples/bold/editor.svelte | 30 + .../editor/examples/bold/extension.ts | 17 + .../components/editor/examples/bold/index.ts | 1 + .../editor/sample/sample-doc-bold.ts | 44 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-bold/src/main.ts | 8 + svelte-bold/src/vite-env.d.ts | 2 + svelte-bold/svelte.config.js | 7 + svelte-bold/tsconfig.json | 21 + svelte-bold/tsconfig.node.json | 9 + svelte-bold/vite.config.ts | 8 + svelte-change-tracking/.gitignore | 4 + svelte-change-tracking/README.md | 15 + svelte-change-tracking/index.html | 12 + svelte-change-tracking/package.json | 28 + svelte-change-tracking/src/App.svelte | 5 + svelte-change-tracking/src/app.css | 12 + .../change-tracking/editor-diff.svelte | 28 + .../change-tracking/editor-main.svelte | 34 + .../examples/change-tracking/editor.svelte | 63 ++ .../editor/examples/change-tracking/index.ts | 1 + svelte-change-tracking/src/main.ts | 8 + svelte-change-tracking/src/vite-env.d.ts | 2 + svelte-change-tracking/svelte.config.js | 7 + svelte-change-tracking/tsconfig.json | 21 + svelte-change-tracking/tsconfig.node.json | 9 + svelte-change-tracking/vite.config.ts | 8 + svelte-code-block-themes/.gitignore | 4 + svelte-code-block-themes/README.md | 15 + svelte-code-block-themes/index.html | 12 + svelte-code-block-themes/package.json | 28 + svelte-code-block-themes/src/App.svelte | 5 + svelte-code-block-themes/src/app.css | 12 + .../examples/code-block-themes/editor.svelte | 30 + .../examples/code-block-themes/extension.ts | 10 + .../examples/code-block-themes/index.ts | 1 + .../code-block-themes/theme-selector.svelte | 29 + .../examples/code-block-themes/toolbar.svelte | 7 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../ui/code-block-view/code-block-view.svelte | 40 + .../editor/ui/code-block-view/index.ts | 15 + svelte-code-block-themes/src/main.ts | 8 + svelte-code-block-themes/src/vite-env.d.ts | 2 + svelte-code-block-themes/svelte.config.js | 7 + svelte-code-block-themes/tsconfig.json | 21 + svelte-code-block-themes/tsconfig.node.json | 9 + svelte-code-block-themes/vite.config.ts | 8 + svelte-code-block/.gitignore | 4 + svelte-code-block/README.md | 15 + svelte-code-block/index.html | 12 + svelte-code-block/package.json | 28 + svelte-code-block/src/App.svelte | 5 + svelte-code-block/src/app.css | 12 + .../editor/examples/code-block/editor.svelte | 30 + .../editor/examples/code-block/extension.ts | 24 + .../editor/examples/code-block/index.ts | 1 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.svelte | 40 + .../editor/ui/code-block-view/index.ts | 15 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-code-block/src/main.ts | 8 + svelte-code-block/src/vite-env.d.ts | 2 + svelte-code-block/svelte.config.js | 7 + svelte-code-block/tsconfig.json | 21 + svelte-code-block/tsconfig.node.json | 9 + svelte-code-block/vite.config.ts | 8 + svelte-code/.gitignore | 4 + svelte-code/README.md | 15 + svelte-code/index.html | 12 + svelte-code/package.json | 28 + svelte-code/src/App.svelte | 5 + svelte-code/src/app.css | 12 + .../editor/examples/code/editor.svelte | 30 + .../editor/examples/code/extension.ts | 17 + .../components/editor/examples/code/index.ts | 1 + .../editor/sample/sample-doc-code.ts | 30 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-code/src/main.ts | 8 + svelte-code/src/vite-env.d.ts | 2 + svelte-code/svelte.config.js | 7 + svelte-code/tsconfig.json | 21 + svelte-code/tsconfig.node.json | 9 + svelte-code/vite.config.ts | 8 + svelte-drop-cursor/.gitignore | 4 + svelte-drop-cursor/README.md | 15 + svelte-drop-cursor/index.html | 12 + svelte-drop-cursor/package.json | 28 + svelte-drop-cursor/src/App.svelte | 5 + svelte-drop-cursor/src/app.css | 12 + .../editor/examples/drop-cursor/editor.svelte | 28 + .../editor/examples/drop-cursor/extension.ts | 23 + .../editor/examples/drop-cursor/index.ts | 1 + .../editor/sample/sample-doc-drop-cursor.ts | 40 + svelte-drop-cursor/src/main.ts | 8 + svelte-drop-cursor/src/vite-env.d.ts | 2 + svelte-drop-cursor/svelte.config.js | 7 + svelte-drop-cursor/tsconfig.json | 21 + svelte-drop-cursor/tsconfig.node.json | 9 + svelte-drop-cursor/vite.config.ts | 8 + svelte-emoji-rules/.gitignore | 4 + svelte-emoji-rules/README.md | 15 + svelte-emoji-rules/index.html | 12 + svelte-emoji-rules/package.json | 28 + svelte-emoji-rules/src/App.svelte | 5 + svelte-emoji-rules/src/app.css | 12 + .../editor/examples/emoji-rules/editor.svelte | 20 + .../editor/examples/emoji-rules/emoji.ts | 15 + .../editor/examples/emoji-rules/extension.ts | 15 + .../editor/examples/emoji-rules/index.ts | 1 + svelte-emoji-rules/src/main.ts | 8 + svelte-emoji-rules/src/vite-env.d.ts | 2 + svelte-emoji-rules/svelte.config.js | 7 + svelte-emoji-rules/tsconfig.json | 21 + svelte-emoji-rules/tsconfig.node.json | 9 + svelte-emoji-rules/vite.config.ts | 8 + svelte-full/.gitignore | 4 + svelte-full/README.md | 15 + svelte-full/index.html | 12 + svelte-full/package.json | 29 + svelte-full/src/App.svelte | 5 + svelte-full/src/app.css | 12 + .../editor/examples/full/editor.svelte | 47 ++ .../editor/examples/full/extension.ts | 34 + .../components/editor/examples/full/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-full.ts | 442 +++++++++++ .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/sample/sample-user-data.ts | 54 ++ .../ui/block-handle/block-handle.svelte | 28 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.svelte | 40 + .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.svelte | 5 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../editor/ui/image-view/image-view.svelte | 97 +++ .../components/editor/ui/image-view/index.ts | 14 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.svelte | 207 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../ui/slash-menu/slash-menu-empty.svelte | 7 + .../ui/slash-menu/slash-menu-item.svelte | 15 + .../editor/ui/slash-menu/slash-menu.svelte | 94 +++ .../editor/ui/table-handle/index.ts | 1 + .../ui/table-handle/table-handle.svelte | 182 +++++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.svelte | 53 ++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.svelte | 70 ++ svelte-full/src/main.ts | 8 + svelte-full/src/vite-env.d.ts | 2 + svelte-full/svelte.config.js | 7 + svelte-full/tsconfig.json | 21 + svelte-full/tsconfig.node.json | 9 + svelte-full/vite.config.ts | 8 + svelte-gap-cursor/.gitignore | 4 + svelte-gap-cursor/README.md | 15 + svelte-gap-cursor/index.html | 12 + svelte-gap-cursor/package.json | 28 + svelte-gap-cursor/src/App.svelte | 5 + svelte-gap-cursor/src/app.css | 12 + .../editor/examples/gap-cursor/editor.svelte | 28 + .../editor/examples/gap-cursor/extension.ts | 19 + .../editor/examples/gap-cursor/index.ts | 1 + .../editor/sample/sample-doc-gap-cursor.ts | 28 + svelte-gap-cursor/src/main.ts | 8 + svelte-gap-cursor/src/vite-env.d.ts | 2 + svelte-gap-cursor/svelte.config.js | 7 + svelte-gap-cursor/tsconfig.json | 21 + svelte-gap-cursor/tsconfig.node.json | 9 + svelte-gap-cursor/vite.config.ts | 8 + svelte-hard-break/.gitignore | 4 + svelte-hard-break/README.md | 15 + svelte-hard-break/index.html | 12 + svelte-hard-break/package.json | 28 + svelte-hard-break/src/App.svelte | 5 + svelte-hard-break/src/app.css | 12 + .../editor/examples/hard-break/editor.svelte | 30 + .../editor/examples/hard-break/extension.ts | 17 + .../editor/examples/hard-break/index.ts | 1 + .../editor/examples/hard-break/toolbar.svelte | 29 + .../editor/sample/sample-doc-hard-break.ts | 68 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + svelte-hard-break/src/main.ts | 8 + svelte-hard-break/src/vite-env.d.ts | 2 + svelte-hard-break/svelte.config.js | 7 + svelte-hard-break/tsconfig.json | 21 + svelte-hard-break/tsconfig.node.json | 9 + svelte-hard-break/vite.config.ts | 8 + svelte-heading/.gitignore | 4 + svelte-heading/README.md | 15 + svelte-heading/index.html | 12 + svelte-heading/package.json | 28 + svelte-heading/src/App.svelte | 5 + svelte-heading/src/app.css | 12 + .../editor/examples/heading/editor.svelte | 30 + .../editor/examples/heading/extension.ts | 17 + .../editor/examples/heading/index.ts | 1 + .../editor/sample/sample-doc-heading.ts | 23 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-heading/src/main.ts | 8 + svelte-heading/src/vite-env.d.ts | 2 + svelte-heading/svelte.config.js | 7 + svelte-heading/tsconfig.json | 21 + svelte-heading/tsconfig.node.json | 9 + svelte-heading/vite.config.ts | 8 + svelte-highlight/.gitignore | 4 + svelte-highlight/README.md | 15 + svelte-highlight/index.html | 12 + svelte-highlight/package.json | 28 + svelte-highlight/src/App.svelte | 5 + svelte-highlight/src/app.css | 12 + .../editor/examples/highlight/editor.svelte | 30 + .../editor/examples/highlight/extension.ts | 17 + .../editor/examples/highlight/index.ts | 1 + .../editor/examples/highlight/toolbar.svelte | 30 + .../editor/sample/sample-doc-highlight.ts | 30 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + svelte-highlight/src/main.ts | 8 + svelte-highlight/src/vite-env.d.ts | 2 + svelte-highlight/svelte.config.js | 7 + svelte-highlight/tsconfig.json | 21 + svelte-highlight/tsconfig.node.json | 9 + svelte-highlight/vite.config.ts | 8 + svelte-horizontal-rule/.gitignore | 4 + svelte-horizontal-rule/README.md | 15 + svelte-horizontal-rule/index.html | 12 + svelte-horizontal-rule/package.json | 28 + svelte-horizontal-rule/src/App.svelte | 5 + svelte-horizontal-rule/src/app.css | 12 + .../examples/horizontal-rule/editor.svelte | 23 + .../examples/horizontal-rule/extension.ts | 17 + .../editor/examples/horizontal-rule/index.ts | 1 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-horizontal-rule/src/main.ts | 8 + svelte-horizontal-rule/src/vite-env.d.ts | 2 + svelte-horizontal-rule/svelte.config.js | 7 + svelte-horizontal-rule/tsconfig.json | 21 + svelte-horizontal-rule/tsconfig.node.json | 9 + svelte-horizontal-rule/vite.config.ts | 8 + svelte-image-view/.gitignore | 4 + svelte-image-view/README.md | 15 + svelte-image-view/index.html | 12 + svelte-image-view/package.json | 28 + svelte-image-view/src/App.svelte | 5 + svelte-image-view/src/app.css | 12 + .../editor/examples/image-view/editor.svelte | 28 + .../editor/examples/image-view/extension.ts | 18 + .../editor/examples/image-view/index.ts | 1 + .../editor/sample/sample-doc-image.ts | 32 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/image-view/image-view.svelte | 97 +++ .../components/editor/ui/image-view/index.ts | 14 + svelte-image-view/src/main.ts | 8 + svelte-image-view/src/vite-env.d.ts | 2 + svelte-image-view/svelte.config.js | 7 + svelte-image-view/tsconfig.json | 21 + svelte-image-view/tsconfig.node.json | 9 + svelte-image-view/vite.config.ts | 8 + svelte-inline-menu/.gitignore | 4 + svelte-inline-menu/README.md | 15 + svelte-inline-menu/index.html | 12 + svelte-inline-menu/package.json | 28 + svelte-inline-menu/src/App.svelte | 5 + svelte-inline-menu/src/app.css | 12 + .../editor/examples/inline-menu/editor.svelte | 30 + .../editor/examples/inline-menu/extension.ts | 7 + .../editor/examples/inline-menu/index.ts | 1 + .../editor/sample/sample-doc-inline-menu.ts | 33 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.svelte | 207 ++++++ svelte-inline-menu/src/main.ts | 8 + svelte-inline-menu/src/vite-env.d.ts | 2 + svelte-inline-menu/svelte.config.js | 7 + svelte-inline-menu/tsconfig.json | 21 + svelte-inline-menu/tsconfig.node.json | 9 + svelte-inline-menu/vite.config.ts | 8 + svelte-italic/.gitignore | 4 + svelte-italic/README.md | 15 + svelte-italic/index.html | 12 + svelte-italic/package.json | 28 + svelte-italic/src/App.svelte | 5 + svelte-italic/src/app.css | 12 + .../editor/examples/italic/editor.svelte | 30 + .../editor/examples/italic/extension.ts | 17 + .../editor/examples/italic/index.ts | 1 + .../editor/sample/sample-doc-italic.ts | 44 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-italic/src/main.ts | 8 + svelte-italic/src/vite-env.d.ts | 2 + svelte-italic/svelte.config.js | 7 + svelte-italic/tsconfig.json | 21 + svelte-italic/tsconfig.node.json | 9 + svelte-italic/vite.config.ts | 8 + svelte-katex/.gitignore | 4 + svelte-katex/README.md | 15 + svelte-katex/index.html | 12 + svelte-katex/package.json | 29 + svelte-katex/src/App.svelte | 5 + svelte-katex/src/app.css | 12 + .../editor/examples/katex/editor.svelte | 28 + .../editor/examples/katex/extension.ts | 17 + .../components/editor/examples/katex/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-tex.ts | 60 ++ svelte-katex/src/main.ts | 8 + svelte-katex/src/vite-env.d.ts | 2 + svelte-katex/svelte.config.js | 7 + svelte-katex/tsconfig.json | 21 + svelte-katex/tsconfig.node.json | 9 + svelte-katex/vite.config.ts | 8 + svelte-keymap/.gitignore | 4 + svelte-keymap/README.md | 15 + svelte-keymap/index.html | 12 + svelte-keymap/package.json | 28 + svelte-keymap/src/App.svelte | 5 + svelte-keymap/src/app.css | 12 + .../editor/examples/keymap/editor.svelte | 43 ++ .../editor/examples/keymap/extension.ts | 8 + .../editor/examples/keymap/index.ts | 1 + .../editor/examples/keymap/toolbar.svelte | 45 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + svelte-keymap/src/main.ts | 8 + svelte-keymap/src/vite-env.d.ts | 2 + svelte-keymap/svelte.config.js | 7 + svelte-keymap/tsconfig.json | 21 + svelte-keymap/tsconfig.node.json | 9 + svelte-keymap/vite.config.ts | 8 + svelte-link-mark-view/.gitignore | 4 + svelte-link-mark-view/README.md | 15 + svelte-link-mark-view/index.html | 12 + svelte-link-mark-view/package.json | 28 + svelte-link-mark-view/src/App.svelte | 5 + svelte-link-mark-view/src/app.css | 12 + .../examples/link-mark-view/editor.svelte | 28 + .../examples/link-mark-view/extension.ts | 17 + .../editor/examples/link-mark-view/index.ts | 1 + .../examples/link-mark-view/link-view.svelte | 50 ++ .../sample/sample-doc-link-mark-view.ts | 30 + svelte-link-mark-view/src/main.ts | 8 + svelte-link-mark-view/src/vite-env.d.ts | 2 + svelte-link-mark-view/svelte.config.js | 7 + svelte-link-mark-view/tsconfig.json | 21 + svelte-link-mark-view/tsconfig.node.json | 9 + svelte-link-mark-view/vite.config.ts | 8 + svelte-link/.gitignore | 4 + svelte-link/README.md | 15 + svelte-link/index.html | 12 + svelte-link/package.json | 28 + svelte-link/src/App.svelte | 5 + svelte-link/src/app.css | 12 + .../editor/examples/link/editor.svelte | 30 + .../editor/examples/link/extension.ts | 17 + .../components/editor/examples/link/index.ts | 1 + .../editor/sample/sample-doc-link.ts | 30 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.svelte | 207 ++++++ svelte-link/src/main.ts | 8 + svelte-link/src/vite-env.d.ts | 2 + svelte-link/svelte.config.js | 7 + svelte-link/tsconfig.json | 21 + svelte-link/tsconfig.node.json | 9 + svelte-link/vite.config.ts | 8 + svelte-list-custom-checkbox/.gitignore | 4 + svelte-list-custom-checkbox/README.md | 15 + svelte-list-custom-checkbox/index.html | 12 + svelte-list-custom-checkbox/package.json | 28 + svelte-list-custom-checkbox/src/App.svelte | 5 + svelte-list-custom-checkbox/src/app.css | 12 + .../list-custom-checkbox/custom-list.css | 75 ++ .../list-custom-checkbox/editor.svelte | 31 + .../list-custom-checkbox/extension.ts | 8 + .../examples/list-custom-checkbox/index.ts | 1 + .../sample/sample-doc-list-custom-checkbox.ts | 38 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-list-custom-checkbox/src/main.ts | 8 + svelte-list-custom-checkbox/src/vite-env.d.ts | 2 + svelte-list-custom-checkbox/svelte.config.js | 7 + svelte-list-custom-checkbox/tsconfig.json | 21 + .../tsconfig.node.json | 9 + svelte-list-custom-checkbox/vite.config.ts | 8 + svelte-list/.gitignore | 4 + svelte-list/README.md | 15 + svelte-list/index.html | 12 + svelte-list/package.json | 28 + svelte-list/src/App.svelte | 5 + svelte-list/src/app.css | 12 + .../editor/examples/list/editor.svelte | 30 + .../editor/examples/list/extension.ts | 17 + .../components/editor/examples/list/index.ts | 1 + .../editor/sample/sample-doc-list.ts | 47 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-list/src/main.ts | 8 + svelte-list/src/vite-env.d.ts | 2 + svelte-list/svelte.config.js | 7 + svelte-list/tsconfig.json | 21 + svelte-list/tsconfig.node.json | 9 + svelte-list/vite.config.ts | 8 + svelte-loro/.gitignore | 4 + svelte-loro/README.md | 15 + svelte-loro/index.html | 12 + svelte-loro/package.json | 31 + svelte-loro/src/App.svelte | 5 + svelte-loro/src/app.css | 12 + .../examples/loro/editor-component.svelte | 32 + .../editor/examples/loro/editor.svelte | 55 ++ .../editor/examples/loro/extension.ts | 47 ++ .../components/editor/examples/loro/index.ts | 1 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-loro/src/main.ts | 8 + svelte-loro/src/vite-env.d.ts | 2 + svelte-loro/svelte.config.js | 7 + svelte-loro/tsconfig.json | 21 + svelte-loro/tsconfig.node.json | 9 + svelte-loro/vite.config.ts | 9 + svelte-mark-rule/.gitignore | 4 + svelte-mark-rule/README.md | 15 + svelte-mark-rule/index.html | 12 + svelte-mark-rule/package.json | 28 + svelte-mark-rule/src/App.svelte | 5 + svelte-mark-rule/src/app.css | 12 + .../editor/examples/mark-rule/editor.svelte | 20 + .../editor/examples/mark-rule/extension.ts | 32 + .../editor/examples/mark-rule/index.ts | 1 + .../editor/examples/mark-rule/issue-link.ts | 32 + svelte-mark-rule/src/main.ts | 8 + svelte-mark-rule/src/vite-env.d.ts | 2 + svelte-mark-rule/svelte.config.js | 7 + svelte-mark-rule/tsconfig.json | 21 + svelte-mark-rule/tsconfig.node.json | 9 + svelte-mark-rule/vite.config.ts | 8 + svelte-minimal/.gitignore | 4 + svelte-minimal/README.md | 15 + svelte-minimal/index.html | 12 + svelte-minimal/package.json | 28 + svelte-minimal/src/App.svelte | 5 + svelte-minimal/src/app.css | 12 + .../editor/examples/minimal/editor.svelte | 15 + .../editor/examples/minimal/index.ts | 1 + svelte-minimal/src/main.ts | 8 + svelte-minimal/src/vite-env.d.ts | 2 + svelte-minimal/svelte.config.js | 7 + svelte-minimal/tsconfig.json | 21 + svelte-minimal/tsconfig.node.json | 9 + svelte-minimal/vite.config.ts | 8 + svelte-page/.gitignore | 4 + svelte-page/README.md | 15 + svelte-page/index.html | 12 + svelte-page/package.json | 28 + svelte-page/src/App.svelte | 5 + svelte-page/src/app.css | 12 + .../editor/examples/page/editor.svelte | 38 + .../editor/examples/page/extension.ts | 9 + .../components/editor/examples/page/index.ts | 1 + .../examples/page/paper-controller.svelte | 143 ++++ .../components/editor/examples/page/zoom.css | 9 + .../editor/sample/sample-doc-page.ts | 98 +++ svelte-page/src/main.ts | 8 + svelte-page/src/vite-env.d.ts | 2 + svelte-page/svelte.config.js | 7 + svelte-page/tsconfig.json | 21 + svelte-page/tsconfig.node.json | 9 + svelte-page/vite.config.ts | 8 + svelte-placeholder/.gitignore | 4 + svelte-placeholder/README.md | 15 + svelte-placeholder/index.html | 12 + svelte-placeholder/package.json | 28 + svelte-placeholder/src/App.svelte | 5 + svelte-placeholder/src/app.css | 12 + .../editor/examples/placeholder/editor.svelte | 31 + .../editor/examples/placeholder/extension.ts | 12 + .../editor/examples/placeholder/index.ts | 1 + svelte-placeholder/src/main.ts | 8 + svelte-placeholder/src/vite-env.d.ts | 2 + svelte-placeholder/svelte.config.js | 7 + svelte-placeholder/tsconfig.json | 21 + svelte-placeholder/tsconfig.node.json | 9 + svelte-placeholder/vite.config.ts | 8 + svelte-readonly/.gitignore | 4 + svelte-readonly/README.md | 15 + svelte-readonly/index.html | 12 + svelte-readonly/package.json | 28 + svelte-readonly/src/App.svelte | 5 + svelte-readonly/src/app.css | 12 + .../editor/examples/readonly/editor.svelte | 30 + .../editor/examples/readonly/extension.ts | 7 + .../editor/examples/readonly/index.ts | 1 + .../editor/examples/readonly/toolbar.svelte | 27 + .../editor/sample/sample-doc-readonly.ts | 16 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + svelte-readonly/src/main.ts | 8 + svelte-readonly/src/vite-env.d.ts | 2 + svelte-readonly/svelte.config.js | 7 + svelte-readonly/tsconfig.json | 21 + svelte-readonly/tsconfig.node.json | 9 + svelte-readonly/vite.config.ts | 8 + svelte-rtl/.gitignore | 4 + svelte-rtl/README.md | 15 + svelte-rtl/index.html | 12 + svelte-rtl/package.json | 28 + svelte-rtl/src/App.svelte | 5 + svelte-rtl/src/app.css | 12 + .../editor/examples/rtl/editor.svelte | 40 + .../components/editor/examples/rtl/index.ts | 1 + .../editor/sample/sample-doc-rtl.ts | 187 +++++ .../editor/sample/sample-uploader.ts | 54 ++ .../ui/block-handle/block-handle.svelte | 28 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../ui/drop-indicator/drop-indicator.svelte | 5 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.svelte | 207 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../ui/slash-menu/slash-menu-empty.svelte | 7 + .../ui/slash-menu/slash-menu-item.svelte | 15 + .../editor/ui/slash-menu/slash-menu.svelte | 94 +++ .../editor/ui/table-handle/index.ts | 1 + .../ui/table-handle/table-handle.svelte | 182 +++++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-rtl/src/main.ts | 8 + svelte-rtl/src/vite-env.d.ts | 2 + svelte-rtl/svelte.config.js | 7 + svelte-rtl/tsconfig.json | 21 + svelte-rtl/tsconfig.node.json | 9 + svelte-rtl/vite.config.ts | 8 + svelte-save-html/.gitignore | 4 + svelte-save-html/README.md | 15 + svelte-save-html/index.html | 12 + svelte-save-html/package.json | 28 + svelte-save-html/src/App.svelte | 5 + svelte-save-html/src/app.css | 12 + .../editor/examples/save-html/editor.svelte | 67 ++ .../editor/examples/save-html/index.ts | 1 + svelte-save-html/src/main.ts | 8 + svelte-save-html/src/vite-env.d.ts | 2 + svelte-save-html/svelte.config.js | 7 + svelte-save-html/tsconfig.json | 21 + svelte-save-html/tsconfig.node.json | 9 + svelte-save-html/vite.config.ts | 8 + svelte-save-json/.gitignore | 4 + svelte-save-json/README.md | 15 + svelte-save-json/index.html | 12 + svelte-save-json/package.json | 28 + svelte-save-json/src/App.svelte | 5 + svelte-save-json/src/app.css | 12 + .../editor/examples/save-json/editor.svelte | 67 ++ .../editor/examples/save-json/index.ts | 1 + svelte-save-json/src/main.ts | 8 + svelte-save-json/src/vite-env.d.ts | 2 + svelte-save-json/svelte.config.js | 7 + svelte-save-json/tsconfig.json | 21 + svelte-save-json/tsconfig.node.json | 9 + svelte-save-json/vite.config.ts | 8 + svelte-save-markdown/.gitignore | 4 + svelte-save-markdown/README.md | 15 + svelte-save-markdown/index.html | 12 + svelte-save-markdown/package.json | 35 + svelte-save-markdown/src/App.svelte | 5 + svelte-save-markdown/src/app.css | 12 + .../examples/save-markdown/editor.svelte | 71 ++ .../editor/examples/save-markdown/index.ts | 1 + .../editor/examples/save-markdown/markdown.ts | 26 + svelte-save-markdown/src/main.ts | 8 + svelte-save-markdown/src/vite-env.d.ts | 2 + svelte-save-markdown/svelte.config.js | 7 + svelte-save-markdown/tsconfig.json | 21 + svelte-save-markdown/tsconfig.node.json | 9 + svelte-save-markdown/vite.config.ts | 8 + svelte-search/.gitignore | 4 + svelte-search/README.md | 15 + svelte-search/index.html | 12 + svelte-search/package.json | 28 + svelte-search/src/App.svelte | 5 + svelte-search/src/app.css | 12 + .../editor/examples/search/editor.svelte | 31 + .../editor/examples/search/extension.ts | 9 + .../editor/examples/search/index.ts | 1 + .../editor/sample/sample-doc-search.ts | 79 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../src/components/editor/ui/search/index.ts | 1 + .../components/editor/ui/search/search.svelte | 168 +++++ svelte-search/src/main.ts | 8 + svelte-search/src/vite-env.d.ts | 2 + svelte-search/svelte.config.js | 7 + svelte-search/tsconfig.json | 21 + svelte-search/tsconfig.node.json | 9 + svelte-search/vite.config.ts | 8 + svelte-slash-menu/.gitignore | 4 + svelte-slash-menu/README.md | 15 + svelte-slash-menu/index.html | 12 + svelte-slash-menu/package.json | 28 + svelte-slash-menu/src/App.svelte | 5 + svelte-slash-menu/src/app.css | 12 + .../editor/examples/slash-menu/editor.svelte | 23 + .../editor/examples/slash-menu/extension.ts | 12 + .../editor/examples/slash-menu/index.ts | 1 + .../components/editor/ui/slash-menu/index.ts | 1 + .../ui/slash-menu/slash-menu-empty.svelte | 7 + .../ui/slash-menu/slash-menu-item.svelte | 15 + .../editor/ui/slash-menu/slash-menu.svelte | 94 +++ svelte-slash-menu/src/main.ts | 8 + svelte-slash-menu/src/vite-env.d.ts | 2 + svelte-slash-menu/svelte.config.js | 7 + svelte-slash-menu/tsconfig.json | 21 + svelte-slash-menu/tsconfig.node.json | 9 + svelte-slash-menu/vite.config.ts | 8 + svelte-strike/.gitignore | 4 + svelte-strike/README.md | 15 + svelte-strike/index.html | 12 + svelte-strike/package.json | 28 + svelte-strike/src/App.svelte | 5 + svelte-strike/src/app.css | 12 + .../editor/examples/strike/editor.svelte | 30 + .../editor/examples/strike/extension.ts | 17 + .../editor/examples/strike/index.ts | 1 + .../editor/examples/strike/toolbar.svelte | 30 + .../editor/sample/sample-doc-strike.ts | 30 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + svelte-strike/src/main.ts | 8 + svelte-strike/src/vite-env.d.ts | 2 + svelte-strike/svelte.config.js | 7 + svelte-strike/tsconfig.json | 21 + svelte-strike/tsconfig.node.json | 9 + svelte-strike/vite.config.ts | 8 + svelte-sub-sup/.gitignore | 4 + svelte-sub-sup/README.md | 15 + svelte-sub-sup/index.html | 12 + svelte-sub-sup/package.json | 28 + svelte-sub-sup/src/App.svelte | 5 + svelte-sub-sup/src/app.css | 12 + .../editor/examples/sub-sup/editor.svelte | 30 + .../editor/examples/sub-sup/extension.ts | 32 + .../editor/examples/sub-sup/index.ts | 1 + .../editor/examples/sub-sup/toolbar.svelte | 42 ++ .../editor/sample/sample-doc-sub-sup.ts | 42 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + svelte-sub-sup/src/main.ts | 8 + svelte-sub-sup/src/vite-env.d.ts | 2 + svelte-sub-sup/svelte.config.js | 7 + svelte-sub-sup/tsconfig.json | 21 + svelte-sub-sup/tsconfig.node.json | 9 + svelte-sub-sup/vite.config.ts | 8 + svelte-table/.gitignore | 4 + svelte-table/README.md | 15 + svelte-table/index.html | 12 + svelte-table/package.json | 28 + svelte-table/src/App.svelte | 5 + svelte-table/src/app.css | 12 + .../editor/examples/table/editor.svelte | 30 + .../editor/examples/table/extension.ts | 20 + .../components/editor/examples/table/index.ts | 1 + .../editor/sample/sample-doc-table.ts | 174 +++++ .../editor/ui/table-handle/index.ts | 1 + .../ui/table-handle/table-handle.svelte | 182 +++++ svelte-table/src/main.ts | 8 + svelte-table/src/vite-env.d.ts | 2 + svelte-table/svelte.config.js | 7 + svelte-table/tsconfig.json | 21 + svelte-table/tsconfig.node.json | 9 + svelte-table/vite.config.ts | 8 + svelte-text-align/.gitignore | 4 + svelte-text-align/README.md | 15 + svelte-text-align/index.html | 12 + svelte-text-align/package.json | 28 + svelte-text-align/src/App.svelte | 5 + svelte-text-align/src/app.css | 12 + .../editor/examples/text-align/editor.svelte | 30 + .../editor/examples/text-align/extension.ts | 12 + .../editor/examples/text-align/index.ts | 1 + .../editor/examples/text-align/toolbar.svelte | 76 ++ .../editor/sample/sample-doc-text-align.ts | 56 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + svelte-text-align/src/main.ts | 8 + svelte-text-align/src/vite-env.d.ts | 2 + svelte-text-align/svelte.config.js | 7 + svelte-text-align/tsconfig.json | 21 + svelte-text-align/tsconfig.node.json | 9 + svelte-text-align/vite.config.ts | 8 + svelte-text-color/.gitignore | 4 + svelte-text-color/README.md | 15 + svelte-text-color/index.html | 12 + svelte-text-color/package.json | 28 + svelte-text-color/src/App.svelte | 5 + svelte-text-color/src/app.css | 12 + .../editor/examples/text-color/editor.svelte | 30 + .../editor/examples/text-color/extension.ts | 14 + .../editor/examples/text-color/index.ts | 1 + .../examples/text-color/inline-menu.svelte | 127 ++++ .../editor/sample/sample-doc-text-color.ts | 120 +++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + svelte-text-color/src/main.ts | 8 + svelte-text-color/src/vite-env.d.ts | 2 + svelte-text-color/svelte.config.js | 7 + svelte-text-color/tsconfig.json | 21 + svelte-text-color/tsconfig.node.json | 9 + svelte-text-color/vite.config.ts | 8 + svelte-toolbar/.gitignore | 4 + svelte-toolbar/README.md | 15 + svelte-toolbar/index.html | 12 + svelte-toolbar/package.json | 28 + svelte-toolbar/src/App.svelte | 5 + svelte-toolbar/src/app.css | 12 + .../editor/examples/toolbar/editor.svelte | 24 + .../editor/examples/toolbar/extension.ts | 8 + .../editor/examples/toolbar/index.ts | 1 + .../editor/sample/sample-uploader.ts | 54 ++ .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-toolbar/src/main.ts | 8 + svelte-toolbar/src/vite-env.d.ts | 2 + svelte-toolbar/svelte.config.js | 7 + svelte-toolbar/tsconfig.json | 21 + svelte-toolbar/tsconfig.node.json | 9 + svelte-toolbar/vite.config.ts | 8 + svelte-typography/.gitignore | 4 + svelte-typography/README.md | 15 + svelte-typography/index.html | 12 + svelte-typography/package.json | 29 + svelte-typography/src/App.svelte | 5 + svelte-typography/src/app.css | 12 + .../editor/examples/typography/editor.svelte | 32 + .../editor/examples/typography/extension.ts | 17 + .../editor/examples/typography/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-typography.ts | 693 ++++++++++++++++++ .../ui/block-handle/block-handle.svelte | 28 + .../editor/ui/block-handle/index.ts | 1 + .../ui/drop-indicator/drop-indicator.svelte | 5 + .../editor/ui/drop-indicator/index.ts | 1 + svelte-typography/src/main.ts | 8 + svelte-typography/src/vite-env.d.ts | 2 + svelte-typography/svelte.config.js | 7 + svelte-typography/tsconfig.json | 21 + svelte-typography/tsconfig.node.json | 9 + svelte-typography/vite.config.ts | 8 + svelte-underline/.gitignore | 4 + svelte-underline/README.md | 15 + svelte-underline/index.html | 12 + svelte-underline/package.json | 28 + svelte-underline/src/App.svelte | 5 + svelte-underline/src/app.css | 12 + .../editor/examples/underline/editor.svelte | 30 + .../editor/examples/underline/extension.ts | 17 + .../editor/examples/underline/index.ts | 1 + .../editor/sample/sample-doc-underline.ts | 30 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-underline/src/main.ts | 8 + svelte-underline/src/vite-env.d.ts | 2 + svelte-underline/svelte.config.js | 7 + svelte-underline/tsconfig.json | 21 + svelte-underline/tsconfig.node.json | 9 + svelte-underline/vite.config.ts | 8 + svelte-unmount/.gitignore | 4 + svelte-unmount/README.md | 15 + svelte-unmount/index.html | 12 + svelte-unmount/package.json | 28 + svelte-unmount/src/App.svelte | 5 + svelte-unmount/src/app.css | 12 + .../examples/unmount/editor-component.svelte | 28 + .../editor/examples/unmount/editor.svelte | 37 + .../unmount/extension-component.svelte | 13 + .../editor/examples/unmount/index.ts | 1 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.svelte | 207 ++++++ svelte-unmount/src/main.ts | 8 + svelte-unmount/src/vite-env.d.ts | 2 + svelte-unmount/svelte.config.js | 7 + svelte-unmount/tsconfig.json | 21 + svelte-unmount/tsconfig.node.json | 9 + svelte-unmount/vite.config.ts | 8 + svelte-user-menu-dynamic/.gitignore | 4 + svelte-user-menu-dynamic/README.md | 15 + svelte-user-menu-dynamic/index.html | 12 + svelte-user-menu-dynamic/package.json | 28 + svelte-user-menu-dynamic/src/App.svelte | 5 + svelte-user-menu-dynamic/src/app.css | 12 + .../examples/user-menu-dynamic/editor.svelte | 22 + .../examples/user-menu-dynamic/extension.ts | 16 + .../examples/user-menu-dynamic/index.ts | 1 + .../use-user-query.svelte.ts | 37 + .../user-menu-dynamic.svelte | 25 + .../editor/sample/sample-query-users.ts | 40 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.svelte | 70 ++ svelte-user-menu-dynamic/src/main.ts | 8 + svelte-user-menu-dynamic/src/vite-env.d.ts | 2 + svelte-user-menu-dynamic/svelte.config.js | 7 + svelte-user-menu-dynamic/tsconfig.json | 21 + svelte-user-menu-dynamic/tsconfig.node.json | 9 + svelte-user-menu-dynamic/vite.config.ts | 8 + svelte-user-menu/.gitignore | 4 + svelte-user-menu/README.md | 15 + svelte-user-menu/index.html | 12 + svelte-user-menu/package.json | 28 + svelte-user-menu/src/App.svelte | 5 + svelte-user-menu/src/app.css | 12 + .../editor/examples/user-menu/editor.svelte | 27 + .../editor/examples/user-menu/extension.ts | 16 + .../editor/examples/user-menu/index.ts | 1 + .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.svelte | 53 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.svelte | 70 ++ svelte-user-menu/src/main.ts | 8 + svelte-user-menu/src/vite-env.d.ts | 2 + svelte-user-menu/svelte.config.js | 7 + svelte-user-menu/tsconfig.json | 21 + svelte-user-menu/tsconfig.node.json | 9 + svelte-user-menu/vite.config.ts | 8 + svelte-word-counter/.gitignore | 4 + svelte-word-counter/README.md | 15 + svelte-word-counter/index.html | 12 + svelte-word-counter/package.json | 28 + svelte-word-counter/src/App.svelte | 5 + svelte-word-counter/src/app.css | 12 + .../examples/word-counter/editor.svelte | 30 + .../editor/examples/word-counter/extension.ts | 8 + .../editor/examples/word-counter/index.ts | 1 + .../editor/sample/sample-doc-word-counter.ts | 16 + .../editor/ui/word-counter/index.ts | 1 + .../ui/word-counter/word-counter.svelte | 20 + svelte-word-counter/src/main.ts | 8 + svelte-word-counter/src/vite-env.d.ts | 2 + svelte-word-counter/svelte.config.js | 7 + svelte-word-counter/tsconfig.json | 21 + svelte-word-counter/tsconfig.node.json | 9 + svelte-word-counter/vite.config.ts | 8 + svelte-yjs/.gitignore | 4 + svelte-yjs/README.md | 15 + svelte-yjs/index.html | 12 + svelte-yjs/package.json | 31 + svelte-yjs/src/App.svelte | 5 + svelte-yjs/src/app.css | 12 + .../examples/yjs/editor-component.svelte | 33 + .../editor/examples/yjs/editor.svelte | 27 + .../editor/examples/yjs/extension.ts | 48 ++ .../components/editor/examples/yjs/index.ts | 1 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ svelte-yjs/src/main.ts | 8 + svelte-yjs/src/vite-env.d.ts | 2 + svelte-yjs/svelte.config.js | 7 + svelte-yjs/tsconfig.json | 21 + svelte-yjs/tsconfig.node.json | 9 + svelte-yjs/vite.config.ts | 8 + sveltekit-full/.gitignore | 4 + sveltekit-full/README.md | 15 + sveltekit-full/package.json | 31 + sveltekit-full/src/app.css | 12 + sveltekit-full/src/app.d.ts | 13 + sveltekit-full/src/app.html | 12 + .../editor/examples/full/editor.svelte | 47 ++ .../editor/examples/full/extension.ts | 34 + .../components/editor/examples/full/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-full.ts | 442 +++++++++++ .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/sample/sample-user-data.ts | 54 ++ .../ui/block-handle/block-handle.svelte | 28 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.svelte | 39 + .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.svelte | 40 + .../editor/ui/code-block-view/index.ts | 15 + .../ui/drop-indicator/drop-indicator.svelte | 5 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.svelte | 121 +++ .../editor/ui/image-upload-popover/index.ts | 1 + .../editor/ui/image-view/image-view.svelte | 97 +++ .../components/editor/ui/image-view/index.ts | 14 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.svelte | 207 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../ui/slash-menu/slash-menu-empty.svelte | 7 + .../ui/slash-menu/slash-menu-item.svelte | 15 + .../editor/ui/slash-menu/slash-menu.svelte | 94 +++ .../editor/ui/table-handle/index.ts | 1 + .../ui/table-handle/table-handle.svelte | 182 +++++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.svelte | 53 ++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../editor/ui/toolbar/toolbar.svelte | 365 +++++++++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.svelte | 70 ++ sveltekit-full/src/lib/App.svelte | 5 + .../src/lib/client-only-editor.svelte | 14 + sveltekit-full/src/lib/editor.svelte | 1 + sveltekit-full/src/routes/+layout.svelte | 5 + sveltekit-full/src/routes/+page.svelte | 7 + sveltekit-full/static/favicon.png | Bin 0 -> 1571 bytes sveltekit-full/svelte.config.js | 18 + sveltekit-full/tsconfig.json | 19 + sveltekit-full/vite.config.ts | 7 + vanilla-minimal/.gitignore | 4 + vanilla-minimal/README.md | 15 + vanilla-minimal/index.html | 11 + vanilla-minimal/package.json | 22 + vanilla-minimal/src/app.css | 12 + .../editor/examples/minimal/editor.ts | 22 + .../editor/examples/minimal/index.ts | 1 + vanilla-minimal/src/editor.ts | 5 + vanilla-minimal/src/main.ts | 11 + vanilla-minimal/tsconfig.json | 26 + vanilla-minimal/vite.config.ts | 6 + vanilla-slash-menu/.gitignore | 4 + vanilla-slash-menu/README.md | 15 + vanilla-slash-menu/index.html | 11 + vanilla-slash-menu/package.json | 22 + vanilla-slash-menu/src/app.css | 12 + .../editor/examples/slash-menu/editor.ts | 39 + .../editor/examples/slash-menu/extension.ts | 12 + .../editor/examples/slash-menu/index.ts | 1 + .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.ts | 17 + .../editor/ui/slash-menu/slash-menu-item.ts | 29 + .../editor/ui/slash-menu/slash-menu.ts | 131 ++++ vanilla-slash-menu/src/editor.ts | 5 + vanilla-slash-menu/src/main.ts | 11 + vanilla-slash-menu/tsconfig.json | 26 + vanilla-slash-menu/vite.config.ts | 6 + vue-block-handle/.gitignore | 4 + vue-block-handle/README.md | 15 + vue-block-handle/index.html | 12 + vue-block-handle/package.json | 27 + vue-block-handle/src/App.vue | 7 + vue-block-handle/src/app.css | 12 + .../editor/examples/block-handle/editor.vue | 38 + .../editor/examples/block-handle/extension.ts | 10 + .../editor/examples/block-handle/index.ts | 1 + .../editor/sample/sample-doc-block-handle.ts | 323 ++++++++ .../editor/ui/block-handle/block-handle.vue | 39 + .../editor/ui/block-handle/index.ts | 1 + .../ui/code-block-view/code-block-view.vue | 41 ++ .../editor/ui/code-block-view/index.ts | 12 + .../ui/drop-indicator/drop-indicator.vue | 7 + .../editor/ui/drop-indicator/index.ts | 1 + vue-block-handle/src/main.ts | 5 + vue-block-handle/tsconfig.app.json | 16 + vue-block-handle/tsconfig.json | 7 + vue-block-handle/tsconfig.node.json | 26 + vue-block-handle/vite.config.ts | 8 + vue-blockquote/.gitignore | 4 + vue-blockquote/README.md | 15 + vue-blockquote/index.html | 12 + vue-blockquote/package.json | 27 + vue-blockquote/src/App.vue | 7 + vue-blockquote/src/app.css | 12 + .../editor/examples/blockquote/editor.vue | 30 + .../editor/examples/blockquote/extension.ts | 17 + .../editor/examples/blockquote/index.ts | 1 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-blockquote/src/main.ts | 5 + vue-blockquote/tsconfig.app.json | 16 + vue-blockquote/tsconfig.json | 7 + vue-blockquote/tsconfig.node.json | 26 + vue-blockquote/vite.config.ts | 8 + vue-bold/.gitignore | 4 + vue-bold/README.md | 15 + vue-bold/index.html | 12 + vue-bold/package.json | 27 + vue-bold/src/App.vue | 7 + vue-bold/src/app.css | 12 + .../editor/examples/bold/editor.vue | 36 + .../editor/examples/bold/extension.ts | 17 + .../components/editor/examples/bold/index.ts | 1 + .../editor/sample/sample-doc-bold.ts | 44 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-bold/src/main.ts | 5 + vue-bold/tsconfig.app.json | 16 + vue-bold/tsconfig.json | 7 + vue-bold/tsconfig.node.json | 26 + vue-bold/vite.config.ts | 8 + vue-change-tracking/.gitignore | 4 + vue-change-tracking/README.md | 15 + vue-change-tracking/index.html | 12 + vue-change-tracking/package.json | 27 + vue-change-tracking/src/App.vue | 7 + vue-change-tracking/src/app.css | 12 + .../examples/change-tracking/editor-diff.vue | 32 + .../examples/change-tracking/editor-main.vue | 40 + .../examples/change-tracking/editor.vue | 71 ++ .../editor/examples/change-tracking/index.ts | 1 + vue-change-tracking/src/main.ts | 5 + vue-change-tracking/tsconfig.app.json | 16 + vue-change-tracking/tsconfig.json | 7 + vue-change-tracking/tsconfig.node.json | 26 + vue-change-tracking/vite.config.ts | 8 + vue-code-block-themes/.gitignore | 4 + vue-code-block-themes/README.md | 15 + vue-code-block-themes/index.html | 12 + vue-code-block-themes/package.json | 27 + vue-code-block-themes/src/App.vue | 7 + vue-code-block-themes/src/app.css | 12 + .../examples/code-block-themes/editor.vue | 39 + .../examples/code-block-themes/extension.ts | 10 + .../examples/code-block-themes/index.ts | 1 + .../code-block-themes/theme-selector.vue | 33 + .../examples/code-block-themes/toolbar.vue | 11 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../ui/code-block-view/code-block-view.vue | 41 ++ .../editor/ui/code-block-view/index.ts | 12 + vue-code-block-themes/src/main.ts | 5 + vue-code-block-themes/tsconfig.app.json | 16 + vue-code-block-themes/tsconfig.json | 7 + vue-code-block-themes/tsconfig.node.json | 26 + vue-code-block-themes/vite.config.ts | 8 + vue-code-block/.gitignore | 4 + vue-code-block/README.md | 15 + vue-code-block/index.html | 12 + vue-code-block/package.json | 27 + vue-code-block/src/App.vue | 7 + vue-code-block/src/app.css | 12 + .../editor/examples/code-block/editor.vue | 39 + .../editor/examples/code-block/extension.ts | 24 + .../editor/examples/code-block/index.ts | 1 + .../editor/sample/sample-doc-code-block.ts | 50 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.vue | 41 ++ .../editor/ui/code-block-view/index.ts | 12 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-code-block/src/main.ts | 5 + vue-code-block/tsconfig.app.json | 16 + vue-code-block/tsconfig.json | 7 + vue-code-block/tsconfig.node.json | 26 + vue-code-block/vite.config.ts | 8 + vue-code/.gitignore | 4 + vue-code/README.md | 15 + vue-code/index.html | 12 + vue-code/package.json | 27 + vue-code/src/App.vue | 7 + vue-code/src/app.css | 12 + .../editor/examples/code/editor.vue | 36 + .../editor/examples/code/extension.ts | 17 + .../components/editor/examples/code/index.ts | 1 + .../editor/sample/sample-doc-code.ts | 30 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-code/src/main.ts | 5 + vue-code/tsconfig.app.json | 16 + vue-code/tsconfig.json | 7 + vue-code/tsconfig.node.json | 26 + vue-code/vite.config.ts | 8 + vue-drop-cursor/.gitignore | 4 + vue-drop-cursor/README.md | 15 + vue-drop-cursor/index.html | 12 + vue-drop-cursor/package.json | 27 + vue-drop-cursor/src/App.vue | 7 + vue-drop-cursor/src/app.css | 12 + .../editor/examples/drop-cursor/editor.vue | 34 + .../editor/examples/drop-cursor/extension.ts | 23 + .../editor/examples/drop-cursor/index.ts | 1 + .../editor/sample/sample-doc-drop-cursor.ts | 40 + vue-drop-cursor/src/main.ts | 5 + vue-drop-cursor/tsconfig.app.json | 16 + vue-drop-cursor/tsconfig.json | 7 + vue-drop-cursor/tsconfig.node.json | 26 + vue-drop-cursor/vite.config.ts | 8 + vue-emoji-rules/.gitignore | 4 + vue-emoji-rules/README.md | 15 + vue-emoji-rules/index.html | 12 + vue-emoji-rules/package.json | 27 + vue-emoji-rules/src/App.vue | 7 + vue-emoji-rules/src/app.css | 12 + .../editor/examples/emoji-rules/editor.vue | 27 + .../editor/examples/emoji-rules/emoji.ts | 15 + .../editor/examples/emoji-rules/extension.ts | 15 + .../editor/examples/emoji-rules/index.ts | 1 + vue-emoji-rules/src/main.ts | 5 + vue-emoji-rules/tsconfig.app.json | 16 + vue-emoji-rules/tsconfig.json | 7 + vue-emoji-rules/tsconfig.node.json | 26 + vue-emoji-rules/vite.config.ts | 8 + vue-full/.gitignore | 4 + vue-full/README.md | 15 + vue-full/index.html | 12 + vue-full/package.json | 28 + vue-full/src/App.vue | 7 + vue-full/src/app.css | 12 + .../editor/examples/full/editor.vue | 53 ++ .../editor/examples/full/extension.ts | 34 + .../components/editor/examples/full/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-full.ts | 442 +++++++++++ .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/sample/sample-user-data.ts | 54 ++ .../editor/ui/block-handle/block-handle.vue | 39 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/code-block-view/code-block-view.vue | 41 ++ .../editor/ui/code-block-view/index.ts | 12 + .../ui/drop-indicator/drop-indicator.vue | 7 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../editor/ui/image-view/image-view.vue | 97 +++ .../components/editor/ui/image-view/index.ts | 11 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.vue | 219 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.vue | 11 + .../editor/ui/slash-menu/slash-menu-item.vue | 24 + .../editor/ui/slash-menu/slash-menu.vue | 106 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.vue | 204 ++++++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.vue | 59 ++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.vue | 74 ++ vue-full/src/main.ts | 5 + vue-full/tsconfig.app.json | 16 + vue-full/tsconfig.json | 7 + vue-full/tsconfig.node.json | 26 + vue-full/vite.config.ts | 8 + vue-gap-cursor/.gitignore | 4 + vue-gap-cursor/README.md | 15 + vue-gap-cursor/index.html | 12 + vue-gap-cursor/package.json | 27 + vue-gap-cursor/src/App.vue | 7 + vue-gap-cursor/src/app.css | 12 + .../editor/examples/gap-cursor/editor.vue | 34 + .../editor/examples/gap-cursor/extension.ts | 19 + .../editor/examples/gap-cursor/index.ts | 1 + .../editor/sample/sample-doc-gap-cursor.ts | 28 + vue-gap-cursor/src/main.ts | 5 + vue-gap-cursor/tsconfig.app.json | 16 + vue-gap-cursor/tsconfig.json | 7 + vue-gap-cursor/tsconfig.node.json | 26 + vue-gap-cursor/vite.config.ts | 8 + vue-hard-break/.gitignore | 4 + vue-hard-break/README.md | 15 + vue-hard-break/index.html | 12 + vue-hard-break/package.json | 27 + vue-hard-break/src/App.vue | 7 + vue-hard-break/src/app.css | 12 + .../editor/examples/hard-break/editor.vue | 36 + .../editor/examples/hard-break/extension.ts | 17 + .../editor/examples/hard-break/index.ts | 1 + .../editor/examples/hard-break/toolbar.vue | 33 + .../editor/sample/sample-doc-hard-break.ts | 68 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + vue-hard-break/src/main.ts | 5 + vue-hard-break/tsconfig.app.json | 16 + vue-hard-break/tsconfig.json | 7 + vue-hard-break/tsconfig.node.json | 26 + vue-hard-break/vite.config.ts | 8 + vue-heading/.gitignore | 4 + vue-heading/README.md | 15 + vue-heading/index.html | 12 + vue-heading/package.json | 27 + vue-heading/src/App.vue | 7 + vue-heading/src/app.css | 12 + .../editor/examples/heading/editor.vue | 36 + .../editor/examples/heading/extension.ts | 17 + .../editor/examples/heading/index.ts | 1 + .../editor/sample/sample-doc-heading.ts | 23 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-heading/src/main.ts | 5 + vue-heading/tsconfig.app.json | 16 + vue-heading/tsconfig.json | 7 + vue-heading/tsconfig.node.json | 26 + vue-heading/vite.config.ts | 8 + vue-highlight/.gitignore | 4 + vue-highlight/README.md | 15 + vue-highlight/index.html | 12 + vue-highlight/package.json | 27 + vue-highlight/src/App.vue | 7 + vue-highlight/src/app.css | 12 + .../editor/examples/highlight/editor.vue | 36 + .../editor/examples/highlight/extension.ts | 17 + .../editor/examples/highlight/index.ts | 1 + .../editor/examples/highlight/toolbar.vue | 34 + .../editor/sample/sample-doc-highlight.ts | 30 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + vue-highlight/src/main.ts | 5 + vue-highlight/tsconfig.app.json | 16 + vue-highlight/tsconfig.json | 7 + vue-highlight/tsconfig.node.json | 26 + vue-highlight/vite.config.ts | 8 + vue-horizontal-rule/.gitignore | 4 + vue-horizontal-rule/README.md | 15 + vue-horizontal-rule/index.html | 12 + vue-horizontal-rule/package.json | 27 + vue-horizontal-rule/src/App.vue | 7 + vue-horizontal-rule/src/app.css | 12 + .../examples/horizontal-rule/editor.vue | 30 + .../examples/horizontal-rule/extension.ts | 17 + .../editor/examples/horizontal-rule/index.ts | 1 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-horizontal-rule/src/main.ts | 5 + vue-horizontal-rule/tsconfig.app.json | 16 + vue-horizontal-rule/tsconfig.json | 7 + vue-horizontal-rule/tsconfig.node.json | 26 + vue-horizontal-rule/vite.config.ts | 8 + vue-image-view/.gitignore | 4 + vue-image-view/README.md | 15 + vue-image-view/index.html | 12 + vue-image-view/package.json | 27 + vue-image-view/src/App.vue | 7 + vue-image-view/src/app.css | 12 + .../editor/examples/image-view/editor.vue | 34 + .../editor/examples/image-view/extension.ts | 18 + .../editor/examples/image-view/index.ts | 1 + .../editor/sample/sample-doc-image.ts | 32 + .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/image-view/image-view.vue | 97 +++ .../components/editor/ui/image-view/index.ts | 11 + vue-image-view/src/main.ts | 5 + vue-image-view/tsconfig.app.json | 16 + vue-image-view/tsconfig.json | 7 + vue-image-view/tsconfig.node.json | 26 + vue-image-view/vite.config.ts | 8 + vue-inline-menu/.gitignore | 4 + vue-inline-menu/README.md | 15 + vue-inline-menu/index.html | 12 + vue-inline-menu/package.json | 27 + vue-inline-menu/src/App.vue | 7 + vue-inline-menu/src/app.css | 12 + .../editor/examples/inline-menu/editor.vue | 36 + .../editor/examples/inline-menu/extension.ts | 7 + .../editor/examples/inline-menu/index.ts | 1 + .../editor/sample/sample-doc-inline-menu.ts | 33 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.vue | 219 ++++++ vue-inline-menu/src/main.ts | 5 + vue-inline-menu/tsconfig.app.json | 16 + vue-inline-menu/tsconfig.json | 7 + vue-inline-menu/tsconfig.node.json | 26 + vue-inline-menu/vite.config.ts | 8 + vue-italic/.gitignore | 4 + vue-italic/README.md | 15 + vue-italic/index.html | 12 + vue-italic/package.json | 27 + vue-italic/src/App.vue | 7 + vue-italic/src/app.css | 12 + .../editor/examples/italic/editor.vue | 36 + .../editor/examples/italic/extension.ts | 17 + .../editor/examples/italic/index.ts | 1 + .../editor/sample/sample-doc-italic.ts | 44 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-italic/src/main.ts | 5 + vue-italic/tsconfig.app.json | 16 + vue-italic/tsconfig.json | 7 + vue-italic/tsconfig.node.json | 26 + vue-italic/vite.config.ts | 8 + vue-katex/.gitignore | 4 + vue-katex/README.md | 15 + vue-katex/index.html | 12 + vue-katex/package.json | 28 + vue-katex/src/App.vue | 7 + vue-katex/src/app.css | 12 + .../editor/examples/katex/editor.vue | 34 + .../editor/examples/katex/extension.ts | 17 + .../components/editor/examples/katex/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-tex.ts | 60 ++ vue-katex/src/main.ts | 5 + vue-katex/tsconfig.app.json | 16 + vue-katex/tsconfig.json | 7 + vue-katex/tsconfig.node.json | 26 + vue-katex/vite.config.ts | 8 + vue-keymap/.gitignore | 4 + vue-keymap/README.md | 15 + vue-keymap/index.html | 12 + vue-keymap/package.json | 27 + vue-keymap/src/App.vue | 7 + vue-keymap/src/app.css | 12 + .../editor/examples/keymap/editor.vue | 49 ++ .../editor/examples/keymap/extension.ts | 8 + .../editor/examples/keymap/index.ts | 1 + .../editor/examples/keymap/toolbar.vue | 38 + .../examples/keymap/use-submit-keymap.ts | 19 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + vue-keymap/src/main.ts | 5 + vue-keymap/tsconfig.app.json | 16 + vue-keymap/tsconfig.json | 7 + vue-keymap/tsconfig.node.json | 26 + vue-keymap/vite.config.ts | 8 + vue-link-mark-view/.gitignore | 4 + vue-link-mark-view/README.md | 15 + vue-link-mark-view/index.html | 12 + vue-link-mark-view/package.json | 27 + vue-link-mark-view/src/App.vue | 7 + vue-link-mark-view/src/app.css | 12 + .../editor/examples/link-mark-view/editor.vue | 34 + .../examples/link-mark-view/extension.ts | 17 + .../editor/examples/link-mark-view/index.ts | 1 + .../examples/link-mark-view/link-view.vue | 48 ++ .../sample/sample-doc-link-mark-view.ts | 30 + vue-link-mark-view/src/main.ts | 5 + vue-link-mark-view/tsconfig.app.json | 16 + vue-link-mark-view/tsconfig.json | 7 + vue-link-mark-view/tsconfig.node.json | 26 + vue-link-mark-view/vite.config.ts | 8 + vue-link/.gitignore | 4 + vue-link/README.md | 15 + vue-link/index.html | 12 + vue-link/package.json | 27 + vue-link/src/App.vue | 7 + vue-link/src/app.css | 12 + .../editor/examples/link/editor.vue | 36 + .../editor/examples/link/extension.ts | 17 + .../components/editor/examples/link/index.ts | 1 + .../editor/sample/sample-doc-link.ts | 30 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.vue | 219 ++++++ vue-link/src/main.ts | 5 + vue-link/tsconfig.app.json | 16 + vue-link/tsconfig.json | 7 + vue-link/tsconfig.node.json | 26 + vue-link/vite.config.ts | 8 + vue-list-custom-checkbox/.gitignore | 4 + vue-list-custom-checkbox/README.md | 15 + vue-list-custom-checkbox/index.html | 12 + vue-list-custom-checkbox/package.json | 27 + vue-list-custom-checkbox/src/App.vue | 7 + vue-list-custom-checkbox/src/app.css | 12 + .../list-custom-checkbox/custom-list.css | 75 ++ .../examples/list-custom-checkbox/editor.vue | 41 ++ .../list-custom-checkbox/extension.ts | 8 + .../examples/list-custom-checkbox/index.ts | 1 + .../sample/sample-doc-list-custom-checkbox.ts | 38 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-list-custom-checkbox/src/main.ts | 5 + vue-list-custom-checkbox/tsconfig.app.json | 16 + vue-list-custom-checkbox/tsconfig.json | 7 + vue-list-custom-checkbox/tsconfig.node.json | 26 + vue-list-custom-checkbox/vite.config.ts | 8 + vue-list/.gitignore | 4 + vue-list/README.md | 15 + vue-list/index.html | 12 + vue-list/package.json | 27 + vue-list/src/App.vue | 7 + vue-list/src/app.css | 12 + .../editor/examples/list/editor.vue | 39 + .../editor/examples/list/extension.ts | 17 + .../components/editor/examples/list/index.ts | 1 + .../editor/sample/sample-doc-list.ts | 47 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-list/src/main.ts | 5 + vue-list/tsconfig.app.json | 16 + vue-list/tsconfig.json | 7 + vue-list/tsconfig.node.json | 26 + vue-list/vite.config.ts | 8 + vue-loro/.gitignore | 4 + vue-loro/README.md | 15 + vue-loro/index.html | 12 + vue-loro/package.json | 30 + vue-loro/src/App.vue | 7 + vue-loro/src/app.css | 12 + .../editor/examples/loro/editor-component.vue | 37 + .../editor/examples/loro/editor.vue | 56 ++ .../editor/examples/loro/extension.ts | 47 ++ .../components/editor/examples/loro/index.ts | 1 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-loro/src/main.ts | 5 + vue-loro/tsconfig.app.json | 16 + vue-loro/tsconfig.json | 7 + vue-loro/tsconfig.node.json | 26 + vue-loro/vite.config.ts | 9 + vue-mark-rule/.gitignore | 4 + vue-mark-rule/README.md | 15 + vue-mark-rule/index.html | 12 + vue-mark-rule/package.json | 27 + vue-mark-rule/src/App.vue | 7 + vue-mark-rule/src/app.css | 12 + .../editor/examples/mark-rule/editor.vue | 27 + .../editor/examples/mark-rule/extension.ts | 32 + .../editor/examples/mark-rule/index.ts | 1 + .../editor/examples/mark-rule/issue-link.ts | 32 + vue-mark-rule/src/main.ts | 5 + vue-mark-rule/tsconfig.app.json | 16 + vue-mark-rule/tsconfig.json | 7 + vue-mark-rule/tsconfig.node.json | 26 + vue-mark-rule/vite.config.ts | 8 + vue-minimal/.gitignore | 4 + vue-minimal/README.md | 15 + vue-minimal/index.html | 12 + vue-minimal/package.json | 27 + vue-minimal/src/App.vue | 7 + vue-minimal/src/app.css | 12 + .../editor/examples/minimal/editor.vue | 20 + .../editor/examples/minimal/index.ts | 1 + vue-minimal/src/main.ts | 5 + vue-minimal/tsconfig.app.json | 16 + vue-minimal/tsconfig.json | 7 + vue-minimal/tsconfig.node.json | 26 + vue-minimal/vite.config.ts | 8 + vue-placeholder/.gitignore | 4 + vue-placeholder/README.md | 15 + vue-placeholder/index.html | 12 + vue-placeholder/package.json | 27 + vue-placeholder/src/App.vue | 7 + vue-placeholder/src/app.css | 12 + .../editor/examples/placeholder/editor.vue | 37 + .../editor/examples/placeholder/extension.ts | 12 + .../editor/examples/placeholder/index.ts | 1 + vue-placeholder/src/main.ts | 5 + vue-placeholder/tsconfig.app.json | 16 + vue-placeholder/tsconfig.json | 7 + vue-placeholder/tsconfig.node.json | 26 + vue-placeholder/vite.config.ts | 8 + vue-readonly/.gitignore | 4 + vue-readonly/README.md | 15 + vue-readonly/index.html | 12 + vue-readonly/package.json | 27 + vue-readonly/src/App.vue | 7 + vue-readonly/src/app.css | 12 + .../editor/examples/readonly/editor.vue | 36 + .../editor/examples/readonly/extension.ts | 7 + .../editor/examples/readonly/index.ts | 1 + .../editor/examples/readonly/toolbar.vue | 17 + .../editor/examples/readonly/use-readonly.ts | 18 + .../editor/sample/sample-doc-readonly.ts | 16 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + vue-readonly/src/main.ts | 5 + vue-readonly/tsconfig.app.json | 16 + vue-readonly/tsconfig.json | 7 + vue-readonly/tsconfig.node.json | 26 + vue-readonly/vite.config.ts | 8 + vue-rtl/.gitignore | 4 + vue-rtl/README.md | 15 + vue-rtl/index.html | 12 + vue-rtl/package.json | 27 + vue-rtl/src/App.vue | 7 + vue-rtl/src/app.css | 12 + .../components/editor/examples/rtl/editor.vue | 47 ++ .../components/editor/examples/rtl/index.ts | 1 + .../editor/sample/sample-doc-rtl.ts | 187 +++++ .../editor/sample/sample-uploader.ts | 54 ++ .../editor/ui/block-handle/block-handle.vue | 39 + .../editor/ui/block-handle/index.ts | 1 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../ui/drop-indicator/drop-indicator.vue | 7 + .../editor/ui/drop-indicator/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.vue | 219 ++++++ .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.vue | 11 + .../editor/ui/slash-menu/slash-menu-item.vue | 24 + .../editor/ui/slash-menu/slash-menu.vue | 106 +++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.vue | 204 ++++++ .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-rtl/src/main.ts | 5 + vue-rtl/tsconfig.app.json | 16 + vue-rtl/tsconfig.json | 7 + vue-rtl/tsconfig.node.json | 26 + vue-rtl/vite.config.ts | 8 + vue-save-html/.gitignore | 4 + vue-save-html/README.md | 15 + vue-save-html/index.html | 12 + vue-save-html/package.json | 27 + vue-save-html/src/App.vue | 7 + vue-save-html/src/app.css | 12 + .../editor/examples/save-html/editor.vue | 75 ++ .../editor/examples/save-html/index.ts | 1 + vue-save-html/src/main.ts | 5 + vue-save-html/tsconfig.app.json | 16 + vue-save-html/tsconfig.json | 7 + vue-save-html/tsconfig.node.json | 26 + vue-save-html/vite.config.ts | 8 + vue-save-json/.gitignore | 4 + vue-save-json/README.md | 15 + vue-save-json/index.html | 12 + vue-save-json/package.json | 27 + vue-save-json/src/App.vue | 7 + vue-save-json/src/app.css | 12 + .../editor/examples/save-json/editor.vue | 75 ++ .../editor/examples/save-json/index.ts | 1 + vue-save-json/src/main.ts | 5 + vue-save-json/tsconfig.app.json | 16 + vue-save-json/tsconfig.json | 7 + vue-save-json/tsconfig.node.json | 26 + vue-save-json/vite.config.ts | 8 + vue-save-markdown/.gitignore | 4 + vue-save-markdown/README.md | 15 + vue-save-markdown/index.html | 12 + vue-save-markdown/package.json | 34 + vue-save-markdown/src/App.vue | 7 + vue-save-markdown/src/app.css | 12 + .../editor/examples/save-markdown/editor.vue | 79 ++ .../editor/examples/save-markdown/index.ts | 1 + .../editor/examples/save-markdown/markdown.ts | 26 + vue-save-markdown/src/main.ts | 5 + vue-save-markdown/tsconfig.app.json | 16 + vue-save-markdown/tsconfig.json | 7 + vue-save-markdown/tsconfig.node.json | 26 + vue-save-markdown/vite.config.ts | 8 + vue-search/.gitignore | 4 + vue-search/README.md | 15 + vue-search/index.html | 12 + vue-search/package.json | 27 + vue-search/src/App.vue | 7 + vue-search/src/app.css | 12 + .../editor/examples/search/editor.vue | 40 + .../editor/examples/search/extension.ts | 9 + .../editor/examples/search/index.ts | 1 + .../editor/sample/sample-doc-search.ts | 79 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../src/components/editor/ui/search/index.ts | 1 + .../components/editor/ui/search/search.vue | 166 +++++ vue-search/src/main.ts | 5 + vue-search/tsconfig.app.json | 16 + vue-search/tsconfig.json | 7 + vue-search/tsconfig.node.json | 26 + vue-search/vite.config.ts | 8 + vue-slash-menu/.gitignore | 4 + vue-slash-menu/README.md | 15 + vue-slash-menu/index.html | 12 + vue-slash-menu/package.json | 27 + vue-slash-menu/src/App.vue | 7 + vue-slash-menu/src/app.css | 12 + .../editor/examples/slash-menu/editor.vue | 30 + .../editor/examples/slash-menu/extension.ts | 12 + .../editor/examples/slash-menu/index.ts | 1 + .../components/editor/ui/slash-menu/index.ts | 1 + .../editor/ui/slash-menu/slash-menu-empty.vue | 11 + .../editor/ui/slash-menu/slash-menu-item.vue | 24 + .../editor/ui/slash-menu/slash-menu.vue | 106 +++ vue-slash-menu/src/main.ts | 5 + vue-slash-menu/tsconfig.app.json | 16 + vue-slash-menu/tsconfig.json | 7 + vue-slash-menu/tsconfig.node.json | 26 + vue-slash-menu/vite.config.ts | 8 + vue-strike/.gitignore | 4 + vue-strike/README.md | 15 + vue-strike/index.html | 12 + vue-strike/package.json | 27 + vue-strike/src/App.vue | 7 + vue-strike/src/app.css | 12 + .../editor/examples/strike/editor.vue | 36 + .../editor/examples/strike/extension.ts | 17 + .../editor/examples/strike/index.ts | 1 + .../editor/examples/strike/toolbar.vue | 34 + .../editor/sample/sample-doc-strike.ts | 30 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + vue-strike/src/main.ts | 5 + vue-strike/tsconfig.app.json | 16 + vue-strike/tsconfig.json | 7 + vue-strike/tsconfig.node.json | 26 + vue-strike/vite.config.ts | 8 + vue-sub-sup/.gitignore | 4 + vue-sub-sup/README.md | 15 + vue-sub-sup/index.html | 12 + vue-sub-sup/package.json | 27 + vue-sub-sup/src/App.vue | 7 + vue-sub-sup/src/app.css | 12 + .../editor/examples/sub-sup/editor.vue | 36 + .../editor/examples/sub-sup/extension.ts | 32 + .../editor/examples/sub-sup/index.ts | 1 + .../editor/examples/sub-sup/toolbar.vue | 46 ++ .../editor/sample/sample-doc-sub-sup.ts | 42 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + vue-sub-sup/src/main.ts | 5 + vue-sub-sup/tsconfig.app.json | 16 + vue-sub-sup/tsconfig.json | 7 + vue-sub-sup/tsconfig.node.json | 26 + vue-sub-sup/vite.config.ts | 8 + vue-table/.gitignore | 4 + vue-table/README.md | 15 + vue-table/index.html | 12 + vue-table/package.json | 27 + vue-table/src/App.vue | 7 + vue-table/src/app.css | 12 + .../editor/examples/table/editor.vue | 36 + .../editor/examples/table/extension.ts | 20 + .../components/editor/examples/table/index.ts | 1 + .../editor/sample/sample-doc-table.ts | 174 +++++ .../editor/ui/table-handle/index.ts | 1 + .../editor/ui/table-handle/table-handle.vue | 204 ++++++ vue-table/src/main.ts | 5 + vue-table/tsconfig.app.json | 16 + vue-table/tsconfig.json | 7 + vue-table/tsconfig.node.json | 26 + vue-table/vite.config.ts | 8 + vue-text-align/.gitignore | 4 + vue-text-align/README.md | 15 + vue-text-align/index.html | 12 + vue-text-align/package.json | 27 + vue-text-align/src/App.vue | 7 + vue-text-align/src/app.css | 12 + .../editor/examples/text-align/editor.vue | 36 + .../editor/examples/text-align/extension.ts | 12 + .../editor/examples/text-align/index.ts | 1 + .../editor/examples/text-align/toolbar.vue | 80 ++ .../editor/sample/sample-doc-text-align.ts | 56 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + vue-text-align/src/main.ts | 5 + vue-text-align/tsconfig.app.json | 16 + vue-text-align/tsconfig.json | 7 + vue-text-align/tsconfig.node.json | 26 + vue-text-align/vite.config.ts | 8 + vue-text-color/.gitignore | 4 + vue-text-color/README.md | 15 + vue-text-color/index.html | 12 + vue-text-color/package.json | 27 + vue-text-color/src/App.vue | 7 + vue-text-color/src/app.css | 12 + .../editor/examples/text-color/editor.vue | 36 + .../editor/examples/text-color/extension.ts | 14 + .../editor/examples/text-color/index.ts | 1 + .../examples/text-color/inline-menu.vue | 142 ++++ .../editor/sample/sample-doc-text-color.ts | 120 +++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + vue-text-color/src/main.ts | 5 + vue-text-color/tsconfig.app.json | 16 + vue-text-color/tsconfig.json | 7 + vue-text-color/tsconfig.node.json | 26 + vue-text-color/vite.config.ts | 8 + vue-toolbar/.gitignore | 4 + vue-toolbar/README.md | 15 + vue-toolbar/index.html | 12 + vue-toolbar/package.json | 27 + vue-toolbar/src/App.vue | 7 + vue-toolbar/src/app.css | 12 + .../editor/examples/toolbar/editor.vue | 31 + .../editor/examples/toolbar/extension.ts | 8 + .../editor/examples/toolbar/index.ts | 1 + .../editor/sample/sample-uploader.ts | 54 ++ .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-toolbar/src/main.ts | 5 + vue-toolbar/tsconfig.app.json | 16 + vue-toolbar/tsconfig.json | 7 + vue-toolbar/tsconfig.node.json | 26 + vue-toolbar/vite.config.ts | 8 + vue-tweet/.gitignore | 4 + vue-tweet/README.md | 15 + vue-tweet/index.html | 12 + vue-tweet/package.json | 28 + vue-tweet/src/App.vue | 7 + vue-tweet/src/app.css | 12 + .../editor/examples/tweet/editor.vue | 59 ++ .../editor/examples/tweet/extension.ts | 43 ++ .../components/editor/examples/tweet/index.ts | 1 + .../editor/examples/tweet/method-select.vue | 42 ++ .../editor/examples/tweet/tweet-view.vue | 28 + .../editor/sample/sample-doc-tweet.ts | 22 + vue-tweet/src/main.ts | 5 + vue-tweet/tsconfig.app.json | 16 + vue-tweet/tsconfig.json | 7 + vue-tweet/tsconfig.node.json | 26 + vue-tweet/vite.config.ts | 8 + vue-typography/.gitignore | 4 + vue-typography/README.md | 15 + vue-typography/index.html | 12 + vue-typography/package.json | 28 + vue-typography/src/App.vue | 7 + vue-typography/src/app.css | 12 + .../editor/examples/typography/editor.vue | 38 + .../editor/examples/typography/extension.ts | 17 + .../editor/examples/typography/index.ts | 1 + .../src/components/editor/sample/katex.ts | 17 + .../editor/sample/sample-doc-typography.ts | 693 ++++++++++++++++++ .../editor/ui/block-handle/block-handle.vue | 39 + .../editor/ui/block-handle/index.ts | 1 + .../ui/drop-indicator/drop-indicator.vue | 7 + .../editor/ui/drop-indicator/index.ts | 1 + vue-typography/src/main.ts | 5 + vue-typography/tsconfig.app.json | 16 + vue-typography/tsconfig.json | 7 + vue-typography/tsconfig.node.json | 26 + vue-typography/vite.config.ts | 8 + vue-underline/.gitignore | 4 + vue-underline/README.md | 15 + vue-underline/index.html | 12 + vue-underline/package.json | 27 + vue-underline/src/App.vue | 7 + vue-underline/src/app.css | 12 + .../editor/examples/underline/editor.vue | 36 + .../editor/examples/underline/extension.ts | 17 + .../editor/examples/underline/index.ts | 1 + .../editor/sample/sample-doc-underline.ts | 30 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-underline/src/main.ts | 5 + vue-underline/tsconfig.app.json | 16 + vue-underline/tsconfig.json | 7 + vue-underline/tsconfig.node.json | 26 + vue-underline/vite.config.ts | 8 + vue-unmount/.gitignore | 4 + vue-unmount/README.md | 15 + vue-unmount/index.html | 12 + vue-unmount/package.json | 27 + vue-unmount/src/App.vue | 7 + vue-unmount/src/app.css | 12 + .../examples/unmount/editor-component.vue | 36 + .../editor/examples/unmount/editor.vue | 37 + .../examples/unmount/extension-component.vue | 19 + .../editor/examples/unmount/index.ts | 1 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../components/editor/ui/inline-menu/index.ts | 1 + .../editor/ui/inline-menu/inline-menu.vue | 219 ++++++ vue-unmount/src/main.ts | 5 + vue-unmount/tsconfig.app.json | 16 + vue-unmount/tsconfig.json | 7 + vue-unmount/tsconfig.node.json | 26 + vue-unmount/vite.config.ts | 8 + vue-user-menu-dynamic/.gitignore | 4 + vue-user-menu-dynamic/README.md | 15 + vue-user-menu-dynamic/index.html | 12 + vue-user-menu-dynamic/package.json | 27 + vue-user-menu-dynamic/src/App.vue | 7 + vue-user-menu-dynamic/src/app.css | 12 + .../examples/user-menu-dynamic/editor.vue | 29 + .../examples/user-menu-dynamic/extension.ts | 16 + .../examples/user-menu-dynamic/index.ts | 1 + .../user-menu-dynamic/use-user-query.ts | 34 + .../user-menu-dynamic/user-menu-dynamic.vue | 29 + .../editor/sample/sample-query-users.ts | 40 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.vue | 74 ++ vue-user-menu-dynamic/src/main.ts | 5 + vue-user-menu-dynamic/tsconfig.app.json | 16 + vue-user-menu-dynamic/tsconfig.json | 7 + vue-user-menu-dynamic/tsconfig.node.json | 26 + vue-user-menu-dynamic/vite.config.ts | 8 + vue-user-menu/.gitignore | 4 + vue-user-menu/README.md | 15 + vue-user-menu/index.html | 12 + vue-user-menu/package.json | 27 + vue-user-menu/src/App.vue | 7 + vue-user-menu/src/app.css | 12 + .../editor/examples/user-menu/editor.vue | 34 + .../editor/examples/user-menu/extension.ts | 16 + .../editor/examples/user-menu/index.ts | 1 + .../editor/sample/sample-tag-data.ts | 12 + .../editor/sample/sample-user-data.ts | 54 ++ .../components/editor/ui/tag-menu/index.ts | 1 + .../editor/ui/tag-menu/tag-menu.vue | 59 ++ .../components/editor/ui/user-menu/index.ts | 1 + .../editor/ui/user-menu/user-menu.vue | 74 ++ vue-user-menu/src/main.ts | 5 + vue-user-menu/tsconfig.app.json | 16 + vue-user-menu/tsconfig.json | 7 + vue-user-menu/tsconfig.node.json | 26 + vue-user-menu/vite.config.ts | 8 + vue-word-counter/.gitignore | 4 + vue-word-counter/README.md | 15 + vue-word-counter/index.html | 12 + vue-word-counter/package.json | 27 + vue-word-counter/src/App.vue | 7 + vue-word-counter/src/app.css | 12 + .../editor/examples/word-counter/editor.vue | 39 + .../editor/examples/word-counter/extension.ts | 8 + .../editor/examples/word-counter/index.ts | 1 + .../editor/sample/sample-doc-word-counter.ts | 16 + .../editor/ui/word-counter/index.ts | 1 + .../editor/ui/word-counter/word-counter.vue | 22 + vue-word-counter/src/main.ts | 5 + vue-word-counter/tsconfig.app.json | 16 + vue-word-counter/tsconfig.json | 7 + vue-word-counter/tsconfig.node.json | 26 + vue-word-counter/vite.config.ts | 8 + vue-yjs/.gitignore | 4 + vue-yjs/README.md | 15 + vue-yjs/index.html | 12 + vue-yjs/package.json | 30 + vue-yjs/src/App.vue | 7 + vue-yjs/src/app.css | 12 + .../editor/examples/yjs/editor-component.vue | 38 + .../components/editor/examples/yjs/editor.vue | 23 + .../editor/examples/yjs/extension.ts | 48 ++ .../components/editor/examples/yjs/index.ts | 1 + .../components/editor/ui/button/button.vue | 42 ++ .../src/components/editor/ui/button/index.ts | 1 + .../image-upload-popover.vue | 139 ++++ .../editor/ui/image-upload-popover/index.ts | 1 + .../src/components/editor/ui/toolbar/index.ts | 1 + .../components/editor/ui/toolbar/toolbar.vue | 347 +++++++++ vue-yjs/src/main.ts | 5 + vue-yjs/tsconfig.app.json | 16 + vue-yjs/tsconfig.json | 7 + vue-yjs/tsconfig.node.json | 26 + vue-yjs/vite.config.ts | 8 + 4971 files changed, 142778 insertions(+) create mode 100644 lit-block-handle/.gitignore create mode 100644 lit-block-handle/README.md create mode 100644 lit-block-handle/index.html create mode 100644 lit-block-handle/package.json create mode 100644 lit-block-handle/src/app.css create mode 100644 lit-block-handle/src/app.ts create mode 100644 lit-block-handle/src/components/editor/examples/block-handle/editor.ts create mode 100644 lit-block-handle/src/components/editor/examples/block-handle/extension.ts create mode 100644 lit-block-handle/src/components/editor/examples/block-handle/index.ts create mode 100644 lit-block-handle/src/components/editor/sample/sample-doc-block-handle.ts create mode 100644 lit-block-handle/src/components/editor/ui/block-handle/block-handle.ts create mode 100644 lit-block-handle/src/components/editor/ui/block-handle/index.ts create mode 100644 lit-block-handle/src/components/editor/ui/code-block-view/code-block-view.ts create mode 100644 lit-block-handle/src/components/editor/ui/code-block-view/index.ts create mode 100644 lit-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.ts create mode 100644 lit-block-handle/src/components/editor/ui/drop-indicator/index.ts create mode 100644 lit-block-handle/src/components/editor/ui/editor-context.ts create mode 100644 lit-block-handle/src/editor.ts create mode 100644 lit-block-handle/tsconfig.json create mode 100644 lit-block-handle/vite.config.ts create mode 100644 lit-code-block/.gitignore create mode 100644 lit-code-block/README.md create mode 100644 lit-code-block/index.html create mode 100644 lit-code-block/package.json create mode 100644 lit-code-block/src/app.css create mode 100644 lit-code-block/src/app.ts create mode 100644 lit-code-block/src/components/editor/examples/code-block/editor.ts create mode 100644 lit-code-block/src/components/editor/examples/code-block/extension.ts create mode 100644 lit-code-block/src/components/editor/examples/code-block/index.ts create mode 100644 lit-code-block/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 lit-code-block/src/components/editor/sample/sample-uploader.ts create mode 100644 lit-code-block/src/components/editor/ui/button/button.ts create mode 100644 lit-code-block/src/components/editor/ui/button/index.ts create mode 100644 lit-code-block/src/components/editor/ui/code-block-view/code-block-view.ts create mode 100644 lit-code-block/src/components/editor/ui/code-block-view/index.ts create mode 100644 lit-code-block/src/components/editor/ui/editor-context.ts create mode 100644 lit-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.ts create mode 100644 lit-code-block/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 lit-code-block/src/components/editor/ui/toolbar/index.ts create mode 100644 lit-code-block/src/components/editor/ui/toolbar/toolbar.ts create mode 100644 lit-code-block/src/editor.ts create mode 100644 lit-code-block/tsconfig.json create mode 100644 lit-code-block/vite.config.ts create mode 100644 lit-minimal/.gitignore create mode 100644 lit-minimal/README.md create mode 100644 lit-minimal/index.html create mode 100644 lit-minimal/package.json create mode 100644 lit-minimal/src/app.css create mode 100644 lit-minimal/src/app.ts create mode 100644 lit-minimal/src/components/editor/examples/minimal/editor.ts create mode 100644 lit-minimal/src/components/editor/examples/minimal/index.ts create mode 100644 lit-minimal/src/editor.ts create mode 100644 lit-minimal/tsconfig.json create mode 100644 lit-minimal/vite.config.ts create mode 100644 lit-slash-menu/.gitignore create mode 100644 lit-slash-menu/README.md create mode 100644 lit-slash-menu/index.html create mode 100644 lit-slash-menu/package.json create mode 100644 lit-slash-menu/src/app.css create mode 100644 lit-slash-menu/src/app.ts create mode 100644 lit-slash-menu/src/components/editor/examples/slash-menu/editor.ts create mode 100644 lit-slash-menu/src/components/editor/examples/slash-menu/extension.ts create mode 100644 lit-slash-menu/src/components/editor/examples/slash-menu/index.ts create mode 100644 lit-slash-menu/src/components/editor/ui/editor-context.ts create mode 100644 lit-slash-menu/src/components/editor/ui/slash-menu/index.ts create mode 100644 lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts create mode 100644 lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts create mode 100644 lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts create mode 100644 lit-slash-menu/src/editor.ts create mode 100644 lit-slash-menu/tsconfig.json create mode 100644 lit-slash-menu/vite.config.ts create mode 100644 lit-table/.gitignore create mode 100644 lit-table/README.md create mode 100644 lit-table/index.html create mode 100644 lit-table/package.json create mode 100644 lit-table/src/app.css create mode 100644 lit-table/src/app.ts create mode 100644 lit-table/src/components/editor/examples/table/editor.ts create mode 100644 lit-table/src/components/editor/examples/table/extension.ts create mode 100644 lit-table/src/components/editor/examples/table/index.ts create mode 100644 lit-table/src/components/editor/sample/sample-doc-table.ts create mode 100644 lit-table/src/components/editor/ui/editor-context.ts create mode 100644 lit-table/src/components/editor/ui/table-handle/index.ts create mode 100644 lit-table/src/components/editor/ui/table-handle/table-handle.ts create mode 100644 lit-table/src/editor.ts create mode 100644 lit-table/tsconfig.json create mode 100644 lit-table/vite.config.ts create mode 100644 lit-toolbar/.gitignore create mode 100644 lit-toolbar/README.md create mode 100644 lit-toolbar/index.html create mode 100644 lit-toolbar/package.json create mode 100644 lit-toolbar/src/app.css create mode 100644 lit-toolbar/src/app.ts create mode 100644 lit-toolbar/src/components/editor/examples/toolbar/editor.ts create mode 100644 lit-toolbar/src/components/editor/examples/toolbar/extension.ts create mode 100644 lit-toolbar/src/components/editor/examples/toolbar/index.ts create mode 100644 lit-toolbar/src/components/editor/sample/sample-uploader.ts create mode 100644 lit-toolbar/src/components/editor/ui/button/button.ts create mode 100644 lit-toolbar/src/components/editor/ui/button/index.ts create mode 100644 lit-toolbar/src/components/editor/ui/editor-context.ts create mode 100644 lit-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.ts create mode 100644 lit-toolbar/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 lit-toolbar/src/components/editor/ui/toolbar/index.ts create mode 100644 lit-toolbar/src/components/editor/ui/toolbar/toolbar.ts create mode 100644 lit-toolbar/src/editor.ts create mode 100644 lit-toolbar/tsconfig.json create mode 100644 lit-toolbar/vite.config.ts create mode 100644 next-full/.gitignore create mode 100644 next-full/README.md create mode 100644 next-full/app/app.css create mode 100644 next-full/app/layout.tsx create mode 100644 next-full/app/page.tsx create mode 100644 next-full/components/editor-dynamic.tsx create mode 100644 next-full/components/editor/examples/full/editor.tsx create mode 100644 next-full/components/editor/examples/full/extension.ts create mode 100644 next-full/components/editor/examples/full/html.ts create mode 100644 next-full/components/editor/examples/full/index.ts create mode 100644 next-full/components/editor/sample/katex.ts create mode 100644 next-full/components/editor/sample/sample-doc-full.ts create mode 100644 next-full/components/editor/sample/sample-tag-data.ts create mode 100644 next-full/components/editor/sample/sample-uploader.ts create mode 100644 next-full/components/editor/sample/sample-user-data.ts create mode 100644 next-full/components/editor/ui/block-handle/block-handle.tsx create mode 100644 next-full/components/editor/ui/block-handle/index.ts create mode 100644 next-full/components/editor/ui/button/button.tsx create mode 100644 next-full/components/editor/ui/button/index.ts create mode 100644 next-full/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 next-full/components/editor/ui/code-block-view/index.ts create mode 100644 next-full/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 next-full/components/editor/ui/drop-indicator/index.ts create mode 100644 next-full/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 next-full/components/editor/ui/image-upload-popover/index.ts create mode 100644 next-full/components/editor/ui/image-view/image-view.tsx create mode 100644 next-full/components/editor/ui/image-view/index.ts create mode 100644 next-full/components/editor/ui/inline-menu/index.ts create mode 100644 next-full/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 next-full/components/editor/ui/slash-menu/index.ts create mode 100644 next-full/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 next-full/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 next-full/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 next-full/components/editor/ui/table-handle/index.ts create mode 100644 next-full/components/editor/ui/table-handle/table-handle.tsx create mode 100644 next-full/components/editor/ui/tag-menu/index.ts create mode 100644 next-full/components/editor/ui/tag-menu/tag-menu.tsx create mode 100644 next-full/components/editor/ui/toolbar/index.ts create mode 100644 next-full/components/editor/ui/toolbar/toolbar.tsx create mode 100644 next-full/components/editor/ui/user-menu/index.ts create mode 100644 next-full/components/editor/ui/user-menu/user-menu.tsx create mode 100644 next-full/next.config.mjs create mode 100644 next-full/package.json create mode 100644 next-full/postcss.config.mjs create mode 100644 next-full/tsconfig.json create mode 100644 nuxt-full/.gitignore create mode 100644 nuxt-full/README.md create mode 100644 nuxt-full/nuxt.config.ts create mode 100644 nuxt-full/package.json create mode 100644 nuxt-full/src/app.css create mode 100644 nuxt-full/src/app.vue create mode 100644 nuxt-full/src/components/editor/examples/full/editor.vue create mode 100644 nuxt-full/src/components/editor/examples/full/extension.ts create mode 100644 nuxt-full/src/components/editor/examples/full/index.ts create mode 100644 nuxt-full/src/components/editor/sample/katex.ts create mode 100644 nuxt-full/src/components/editor/sample/sample-doc-full.ts create mode 100644 nuxt-full/src/components/editor/sample/sample-tag-data.ts create mode 100644 nuxt-full/src/components/editor/sample/sample-uploader.ts create mode 100644 nuxt-full/src/components/editor/sample/sample-user-data.ts create mode 100644 nuxt-full/src/components/editor/ui/block-handle/block-handle.vue create mode 100644 nuxt-full/src/components/editor/ui/block-handle/index.ts create mode 100644 nuxt-full/src/components/editor/ui/button/button.vue create mode 100644 nuxt-full/src/components/editor/ui/button/index.ts create mode 100644 nuxt-full/src/components/editor/ui/code-block-view/code-block-view.vue create mode 100644 nuxt-full/src/components/editor/ui/code-block-view/index.ts create mode 100644 nuxt-full/src/components/editor/ui/drop-indicator/drop-indicator.vue create mode 100644 nuxt-full/src/components/editor/ui/drop-indicator/index.ts create mode 100644 nuxt-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 nuxt-full/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 nuxt-full/src/components/editor/ui/image-view/image-view.vue create mode 100644 nuxt-full/src/components/editor/ui/image-view/index.ts create mode 100644 nuxt-full/src/components/editor/ui/inline-menu/index.ts create mode 100644 nuxt-full/src/components/editor/ui/inline-menu/inline-menu.vue create mode 100644 nuxt-full/src/components/editor/ui/slash-menu/index.ts create mode 100644 nuxt-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue create mode 100644 nuxt-full/src/components/editor/ui/slash-menu/slash-menu-item.vue create mode 100644 nuxt-full/src/components/editor/ui/slash-menu/slash-menu.vue create mode 100644 nuxt-full/src/components/editor/ui/table-handle/index.ts create mode 100644 nuxt-full/src/components/editor/ui/table-handle/table-handle.vue create mode 100644 nuxt-full/src/components/editor/ui/tag-menu/index.ts create mode 100644 nuxt-full/src/components/editor/ui/tag-menu/tag-menu.vue create mode 100644 nuxt-full/src/components/editor/ui/toolbar/index.ts create mode 100644 nuxt-full/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 nuxt-full/src/components/editor/ui/user-menu/index.ts create mode 100644 nuxt-full/src/components/editor/ui/user-menu/user-menu.vue create mode 100644 nuxt-full/src/editor.vue create mode 100644 nuxt-full/tsconfig.json create mode 100644 preact-block-handle/.gitignore create mode 100644 preact-block-handle/README.md create mode 100644 preact-block-handle/index.html create mode 100644 preact-block-handle/package.json create mode 100644 preact-block-handle/src/App.tsx create mode 100644 preact-block-handle/src/app.css create mode 100644 preact-block-handle/src/components/editor/examples/block-handle/editor.tsx create mode 100644 preact-block-handle/src/components/editor/examples/block-handle/extension.ts create mode 100644 preact-block-handle/src/components/editor/examples/block-handle/index.ts create mode 100644 preact-block-handle/src/components/editor/sample/sample-doc-block-handle.ts create mode 100644 preact-block-handle/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 preact-block-handle/src/components/editor/ui/block-handle/index.ts create mode 100644 preact-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 preact-block-handle/src/components/editor/ui/code-block-view/index.ts create mode 100644 preact-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 preact-block-handle/src/components/editor/ui/drop-indicator/index.ts create mode 100644 preact-block-handle/src/main.tsx create mode 100644 preact-block-handle/tsconfig.app.json create mode 100644 preact-block-handle/tsconfig.json create mode 100644 preact-block-handle/tsconfig.node.json create mode 100644 preact-block-handle/vite.config.ts create mode 100644 preact-blockquote/.gitignore create mode 100644 preact-blockquote/README.md create mode 100644 preact-blockquote/index.html create mode 100644 preact-blockquote/package.json create mode 100644 preact-blockquote/src/App.tsx create mode 100644 preact-blockquote/src/app.css create mode 100644 preact-blockquote/src/components/editor/examples/blockquote/editor.tsx create mode 100644 preact-blockquote/src/components/editor/examples/blockquote/extension.ts create mode 100644 preact-blockquote/src/components/editor/examples/blockquote/index.ts create mode 100644 preact-blockquote/src/components/editor/ui/button/button.tsx create mode 100644 preact-blockquote/src/components/editor/ui/button/index.ts create mode 100644 preact-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-blockquote/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-blockquote/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-blockquote/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-blockquote/src/main.tsx create mode 100644 preact-blockquote/tsconfig.app.json create mode 100644 preact-blockquote/tsconfig.json create mode 100644 preact-blockquote/tsconfig.node.json create mode 100644 preact-blockquote/vite.config.ts create mode 100644 preact-bold/.gitignore create mode 100644 preact-bold/README.md create mode 100644 preact-bold/index.html create mode 100644 preact-bold/package.json create mode 100644 preact-bold/src/App.tsx create mode 100644 preact-bold/src/app.css create mode 100644 preact-bold/src/components/editor/examples/bold/editor.tsx create mode 100644 preact-bold/src/components/editor/examples/bold/extension.ts create mode 100644 preact-bold/src/components/editor/examples/bold/index.ts create mode 100644 preact-bold/src/components/editor/sample/sample-doc-bold.ts create mode 100644 preact-bold/src/components/editor/ui/button/button.tsx create mode 100644 preact-bold/src/components/editor/ui/button/index.ts create mode 100644 preact-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-bold/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-bold/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-bold/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-bold/src/main.tsx create mode 100644 preact-bold/tsconfig.app.json create mode 100644 preact-bold/tsconfig.json create mode 100644 preact-bold/tsconfig.node.json create mode 100644 preact-bold/vite.config.ts create mode 100644 preact-change-tracking/.gitignore create mode 100644 preact-change-tracking/README.md create mode 100644 preact-change-tracking/index.html create mode 100644 preact-change-tracking/package.json create mode 100644 preact-change-tracking/src/App.tsx create mode 100644 preact-change-tracking/src/app.css create mode 100644 preact-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx create mode 100644 preact-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx create mode 100644 preact-change-tracking/src/components/editor/examples/change-tracking/editor.tsx create mode 100644 preact-change-tracking/src/components/editor/examples/change-tracking/index.ts create mode 100644 preact-change-tracking/src/main.tsx create mode 100644 preact-change-tracking/tsconfig.app.json create mode 100644 preact-change-tracking/tsconfig.json create mode 100644 preact-change-tracking/tsconfig.node.json create mode 100644 preact-change-tracking/vite.config.ts create mode 100644 preact-code-block-themes/.gitignore create mode 100644 preact-code-block-themes/README.md create mode 100644 preact-code-block-themes/index.html create mode 100644 preact-code-block-themes/package.json create mode 100644 preact-code-block-themes/src/App.tsx create mode 100644 preact-code-block-themes/src/app.css create mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx create mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts create mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/index.ts create mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx create mode 100644 preact-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx create mode 100644 preact-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 preact-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 preact-code-block-themes/src/components/editor/ui/code-block-view/index.ts create mode 100644 preact-code-block-themes/src/main.tsx create mode 100644 preact-code-block-themes/tsconfig.app.json create mode 100644 preact-code-block-themes/tsconfig.json create mode 100644 preact-code-block-themes/tsconfig.node.json create mode 100644 preact-code-block-themes/vite.config.ts create mode 100644 preact-code-block/.gitignore create mode 100644 preact-code-block/README.md create mode 100644 preact-code-block/index.html create mode 100644 preact-code-block/package.json create mode 100644 preact-code-block/src/App.tsx create mode 100644 preact-code-block/src/app.css create mode 100644 preact-code-block/src/components/editor/examples/code-block/editor.tsx create mode 100644 preact-code-block/src/components/editor/examples/code-block/extension.ts create mode 100644 preact-code-block/src/components/editor/examples/code-block/index.ts create mode 100644 preact-code-block/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 preact-code-block/src/components/editor/ui/button/button.tsx create mode 100644 preact-code-block/src/components/editor/ui/button/index.ts create mode 100644 preact-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 preact-code-block/src/components/editor/ui/code-block-view/index.ts create mode 100644 preact-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-code-block/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-code-block/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-code-block/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-code-block/src/main.tsx create mode 100644 preact-code-block/tsconfig.app.json create mode 100644 preact-code-block/tsconfig.json create mode 100644 preact-code-block/tsconfig.node.json create mode 100644 preact-code-block/vite.config.ts create mode 100644 preact-code/.gitignore create mode 100644 preact-code/README.md create mode 100644 preact-code/index.html create mode 100644 preact-code/package.json create mode 100644 preact-code/src/App.tsx create mode 100644 preact-code/src/app.css create mode 100644 preact-code/src/components/editor/examples/code/editor.tsx create mode 100644 preact-code/src/components/editor/examples/code/extension.ts create mode 100644 preact-code/src/components/editor/examples/code/index.ts create mode 100644 preact-code/src/components/editor/sample/sample-doc-code.ts create mode 100644 preact-code/src/components/editor/ui/button/button.tsx create mode 100644 preact-code/src/components/editor/ui/button/index.ts create mode 100644 preact-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-code/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-code/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-code/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-code/src/main.tsx create mode 100644 preact-code/tsconfig.app.json create mode 100644 preact-code/tsconfig.json create mode 100644 preact-code/tsconfig.node.json create mode 100644 preact-code/vite.config.ts create mode 100644 preact-drop-cursor/.gitignore create mode 100644 preact-drop-cursor/README.md create mode 100644 preact-drop-cursor/index.html create mode 100644 preact-drop-cursor/package.json create mode 100644 preact-drop-cursor/src/App.tsx create mode 100644 preact-drop-cursor/src/app.css create mode 100644 preact-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx create mode 100644 preact-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts create mode 100644 preact-drop-cursor/src/components/editor/examples/drop-cursor/index.ts create mode 100644 preact-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts create mode 100644 preact-drop-cursor/src/main.tsx create mode 100644 preact-drop-cursor/tsconfig.app.json create mode 100644 preact-drop-cursor/tsconfig.json create mode 100644 preact-drop-cursor/tsconfig.node.json create mode 100644 preact-drop-cursor/vite.config.ts create mode 100644 preact-emoji-rules/.gitignore create mode 100644 preact-emoji-rules/README.md create mode 100644 preact-emoji-rules/index.html create mode 100644 preact-emoji-rules/package.json create mode 100644 preact-emoji-rules/src/App.tsx create mode 100644 preact-emoji-rules/src/app.css create mode 100644 preact-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx create mode 100644 preact-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts create mode 100644 preact-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts create mode 100644 preact-emoji-rules/src/components/editor/examples/emoji-rules/index.ts create mode 100644 preact-emoji-rules/src/main.tsx create mode 100644 preact-emoji-rules/tsconfig.app.json create mode 100644 preact-emoji-rules/tsconfig.json create mode 100644 preact-emoji-rules/tsconfig.node.json create mode 100644 preact-emoji-rules/vite.config.ts create mode 100644 preact-full/.gitignore create mode 100644 preact-full/README.md create mode 100644 preact-full/index.html create mode 100644 preact-full/package.json create mode 100644 preact-full/src/App.tsx create mode 100644 preact-full/src/app.css create mode 100644 preact-full/src/components/editor/examples/full/editor.tsx create mode 100644 preact-full/src/components/editor/examples/full/extension.ts create mode 100644 preact-full/src/components/editor/examples/full/index.ts create mode 100644 preact-full/src/components/editor/sample/katex.ts create mode 100644 preact-full/src/components/editor/sample/sample-doc-full.ts create mode 100644 preact-full/src/components/editor/sample/sample-tag-data.ts create mode 100644 preact-full/src/components/editor/sample/sample-uploader.ts create mode 100644 preact-full/src/components/editor/sample/sample-user-data.ts create mode 100644 preact-full/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 preact-full/src/components/editor/ui/block-handle/index.ts create mode 100644 preact-full/src/components/editor/ui/button/button.tsx create mode 100644 preact-full/src/components/editor/ui/button/index.ts create mode 100644 preact-full/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 preact-full/src/components/editor/ui/code-block-view/index.ts create mode 100644 preact-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 preact-full/src/components/editor/ui/drop-indicator/index.ts create mode 100644 preact-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-full/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-full/src/components/editor/ui/image-view/image-view.tsx create mode 100644 preact-full/src/components/editor/ui/image-view/index.ts create mode 100644 preact-full/src/components/editor/ui/inline-menu/index.ts create mode 100644 preact-full/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 preact-full/src/components/editor/ui/slash-menu/index.ts create mode 100644 preact-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 preact-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 preact-full/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 preact-full/src/components/editor/ui/table-handle/index.ts create mode 100644 preact-full/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 preact-full/src/components/editor/ui/tag-menu/index.ts create mode 100644 preact-full/src/components/editor/ui/tag-menu/tag-menu.tsx create mode 100644 preact-full/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-full/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-full/src/components/editor/ui/user-menu/index.ts create mode 100644 preact-full/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 preact-full/src/main.tsx create mode 100644 preact-full/tsconfig.app.json create mode 100644 preact-full/tsconfig.json create mode 100644 preact-full/tsconfig.node.json create mode 100644 preact-full/vite.config.ts create mode 100644 preact-gap-cursor/.gitignore create mode 100644 preact-gap-cursor/README.md create mode 100644 preact-gap-cursor/index.html create mode 100644 preact-gap-cursor/package.json create mode 100644 preact-gap-cursor/src/App.tsx create mode 100644 preact-gap-cursor/src/app.css create mode 100644 preact-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx create mode 100644 preact-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts create mode 100644 preact-gap-cursor/src/components/editor/examples/gap-cursor/index.ts create mode 100644 preact-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts create mode 100644 preact-gap-cursor/src/main.tsx create mode 100644 preact-gap-cursor/tsconfig.app.json create mode 100644 preact-gap-cursor/tsconfig.json create mode 100644 preact-gap-cursor/tsconfig.node.json create mode 100644 preact-gap-cursor/vite.config.ts create mode 100644 preact-hard-break/.gitignore create mode 100644 preact-hard-break/README.md create mode 100644 preact-hard-break/index.html create mode 100644 preact-hard-break/package.json create mode 100644 preact-hard-break/src/App.tsx create mode 100644 preact-hard-break/src/app.css create mode 100644 preact-hard-break/src/components/editor/examples/hard-break/editor.tsx create mode 100644 preact-hard-break/src/components/editor/examples/hard-break/extension.ts create mode 100644 preact-hard-break/src/components/editor/examples/hard-break/index.ts create mode 100644 preact-hard-break/src/components/editor/examples/hard-break/toolbar.tsx create mode 100644 preact-hard-break/src/components/editor/sample/sample-doc-hard-break.ts create mode 100644 preact-hard-break/src/components/editor/ui/button/button.tsx create mode 100644 preact-hard-break/src/components/editor/ui/button/index.ts create mode 100644 preact-hard-break/src/main.tsx create mode 100644 preact-hard-break/tsconfig.app.json create mode 100644 preact-hard-break/tsconfig.json create mode 100644 preact-hard-break/tsconfig.node.json create mode 100644 preact-hard-break/vite.config.ts create mode 100644 preact-heading/.gitignore create mode 100644 preact-heading/README.md create mode 100644 preact-heading/index.html create mode 100644 preact-heading/package.json create mode 100644 preact-heading/src/App.tsx create mode 100644 preact-heading/src/app.css create mode 100644 preact-heading/src/components/editor/examples/heading/editor.tsx create mode 100644 preact-heading/src/components/editor/examples/heading/extension.ts create mode 100644 preact-heading/src/components/editor/examples/heading/index.ts create mode 100644 preact-heading/src/components/editor/sample/sample-doc-heading.ts create mode 100644 preact-heading/src/components/editor/ui/button/button.tsx create mode 100644 preact-heading/src/components/editor/ui/button/index.ts create mode 100644 preact-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-heading/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-heading/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-heading/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-heading/src/main.tsx create mode 100644 preact-heading/tsconfig.app.json create mode 100644 preact-heading/tsconfig.json create mode 100644 preact-heading/tsconfig.node.json create mode 100644 preact-heading/vite.config.ts create mode 100644 preact-highlight/.gitignore create mode 100644 preact-highlight/README.md create mode 100644 preact-highlight/index.html create mode 100644 preact-highlight/package.json create mode 100644 preact-highlight/src/App.tsx create mode 100644 preact-highlight/src/app.css create mode 100644 preact-highlight/src/components/editor/examples/highlight/editor.tsx create mode 100644 preact-highlight/src/components/editor/examples/highlight/extension.ts create mode 100644 preact-highlight/src/components/editor/examples/highlight/index.ts create mode 100644 preact-highlight/src/components/editor/examples/highlight/toolbar.tsx create mode 100644 preact-highlight/src/components/editor/sample/sample-doc-highlight.ts create mode 100644 preact-highlight/src/components/editor/ui/button/button.tsx create mode 100644 preact-highlight/src/components/editor/ui/button/index.ts create mode 100644 preact-highlight/src/main.tsx create mode 100644 preact-highlight/tsconfig.app.json create mode 100644 preact-highlight/tsconfig.json create mode 100644 preact-highlight/tsconfig.node.json create mode 100644 preact-highlight/vite.config.ts create mode 100644 preact-horizontal-rule/.gitignore create mode 100644 preact-horizontal-rule/README.md create mode 100644 preact-horizontal-rule/index.html create mode 100644 preact-horizontal-rule/package.json create mode 100644 preact-horizontal-rule/src/App.tsx create mode 100644 preact-horizontal-rule/src/app.css create mode 100644 preact-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx create mode 100644 preact-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts create mode 100644 preact-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts create mode 100644 preact-horizontal-rule/src/components/editor/ui/button/button.tsx create mode 100644 preact-horizontal-rule/src/components/editor/ui/button/index.ts create mode 100644 preact-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-horizontal-rule/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-horizontal-rule/src/main.tsx create mode 100644 preact-horizontal-rule/tsconfig.app.json create mode 100644 preact-horizontal-rule/tsconfig.json create mode 100644 preact-horizontal-rule/tsconfig.node.json create mode 100644 preact-horizontal-rule/vite.config.ts create mode 100644 preact-image-view/.gitignore create mode 100644 preact-image-view/README.md create mode 100644 preact-image-view/index.html create mode 100644 preact-image-view/package.json create mode 100644 preact-image-view/src/App.tsx create mode 100644 preact-image-view/src/app.css create mode 100644 preact-image-view/src/components/editor/examples/image-view/editor.tsx create mode 100644 preact-image-view/src/components/editor/examples/image-view/extension.ts create mode 100644 preact-image-view/src/components/editor/examples/image-view/index.ts create mode 100644 preact-image-view/src/components/editor/sample/sample-doc-image.ts create mode 100644 preact-image-view/src/components/editor/sample/sample-uploader.ts create mode 100644 preact-image-view/src/components/editor/ui/image-view/image-view.tsx create mode 100644 preact-image-view/src/components/editor/ui/image-view/index.ts create mode 100644 preact-image-view/src/main.tsx create mode 100644 preact-image-view/tsconfig.app.json create mode 100644 preact-image-view/tsconfig.json create mode 100644 preact-image-view/tsconfig.node.json create mode 100644 preact-image-view/vite.config.ts create mode 100644 preact-inline-menu/.gitignore create mode 100644 preact-inline-menu/README.md create mode 100644 preact-inline-menu/index.html create mode 100644 preact-inline-menu/package.json create mode 100644 preact-inline-menu/src/App.tsx create mode 100644 preact-inline-menu/src/app.css create mode 100644 preact-inline-menu/src/components/editor/examples/inline-menu/editor.tsx create mode 100644 preact-inline-menu/src/components/editor/examples/inline-menu/extension.ts create mode 100644 preact-inline-menu/src/components/editor/examples/inline-menu/index.ts create mode 100644 preact-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts create mode 100644 preact-inline-menu/src/components/editor/ui/button/button.tsx create mode 100644 preact-inline-menu/src/components/editor/ui/button/index.ts create mode 100644 preact-inline-menu/src/components/editor/ui/inline-menu/index.ts create mode 100644 preact-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 preact-inline-menu/src/main.tsx create mode 100644 preact-inline-menu/tsconfig.app.json create mode 100644 preact-inline-menu/tsconfig.json create mode 100644 preact-inline-menu/tsconfig.node.json create mode 100644 preact-inline-menu/vite.config.ts create mode 100644 preact-italic/.gitignore create mode 100644 preact-italic/README.md create mode 100644 preact-italic/index.html create mode 100644 preact-italic/package.json create mode 100644 preact-italic/src/App.tsx create mode 100644 preact-italic/src/app.css create mode 100644 preact-italic/src/components/editor/examples/italic/editor.tsx create mode 100644 preact-italic/src/components/editor/examples/italic/extension.ts create mode 100644 preact-italic/src/components/editor/examples/italic/index.ts create mode 100644 preact-italic/src/components/editor/sample/sample-doc-italic.ts create mode 100644 preact-italic/src/components/editor/ui/button/button.tsx create mode 100644 preact-italic/src/components/editor/ui/button/index.ts create mode 100644 preact-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-italic/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-italic/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-italic/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-italic/src/main.tsx create mode 100644 preact-italic/tsconfig.app.json create mode 100644 preact-italic/tsconfig.json create mode 100644 preact-italic/tsconfig.node.json create mode 100644 preact-italic/vite.config.ts create mode 100644 preact-katex/.gitignore create mode 100644 preact-katex/README.md create mode 100644 preact-katex/index.html create mode 100644 preact-katex/package.json create mode 100644 preact-katex/src/App.tsx create mode 100644 preact-katex/src/app.css create mode 100644 preact-katex/src/components/editor/examples/katex/editor.tsx create mode 100644 preact-katex/src/components/editor/examples/katex/extension.ts create mode 100644 preact-katex/src/components/editor/examples/katex/index.ts create mode 100644 preact-katex/src/components/editor/sample/katex.ts create mode 100644 preact-katex/src/components/editor/sample/sample-doc-tex.ts create mode 100644 preact-katex/src/main.tsx create mode 100644 preact-katex/tsconfig.app.json create mode 100644 preact-katex/tsconfig.json create mode 100644 preact-katex/tsconfig.node.json create mode 100644 preact-katex/vite.config.ts create mode 100644 preact-keymap/.gitignore create mode 100644 preact-keymap/README.md create mode 100644 preact-keymap/index.html create mode 100644 preact-keymap/package.json create mode 100644 preact-keymap/src/App.tsx create mode 100644 preact-keymap/src/app.css create mode 100644 preact-keymap/src/components/editor/examples/keymap/editor.tsx create mode 100644 preact-keymap/src/components/editor/examples/keymap/extension.ts create mode 100644 preact-keymap/src/components/editor/examples/keymap/index.ts create mode 100644 preact-keymap/src/components/editor/examples/keymap/toolbar.tsx create mode 100644 preact-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts create mode 100644 preact-keymap/src/components/editor/ui/button/button.tsx create mode 100644 preact-keymap/src/components/editor/ui/button/index.ts create mode 100644 preact-keymap/src/main.tsx create mode 100644 preact-keymap/tsconfig.app.json create mode 100644 preact-keymap/tsconfig.json create mode 100644 preact-keymap/tsconfig.node.json create mode 100644 preact-keymap/vite.config.ts create mode 100644 preact-link-mark-view/.gitignore create mode 100644 preact-link-mark-view/README.md create mode 100644 preact-link-mark-view/index.html create mode 100644 preact-link-mark-view/package.json create mode 100644 preact-link-mark-view/src/App.tsx create mode 100644 preact-link-mark-view/src/app.css create mode 100644 preact-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx create mode 100644 preact-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts create mode 100644 preact-link-mark-view/src/components/editor/examples/link-mark-view/index.ts create mode 100644 preact-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx create mode 100644 preact-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts create mode 100644 preact-link-mark-view/src/main.tsx create mode 100644 preact-link-mark-view/tsconfig.app.json create mode 100644 preact-link-mark-view/tsconfig.json create mode 100644 preact-link-mark-view/tsconfig.node.json create mode 100644 preact-link-mark-view/vite.config.ts create mode 100644 preact-link/.gitignore create mode 100644 preact-link/README.md create mode 100644 preact-link/index.html create mode 100644 preact-link/package.json create mode 100644 preact-link/src/App.tsx create mode 100644 preact-link/src/app.css create mode 100644 preact-link/src/components/editor/examples/link/editor.tsx create mode 100644 preact-link/src/components/editor/examples/link/extension.ts create mode 100644 preact-link/src/components/editor/examples/link/index.ts create mode 100644 preact-link/src/components/editor/sample/sample-doc-link.ts create mode 100644 preact-link/src/components/editor/ui/button/button.tsx create mode 100644 preact-link/src/components/editor/ui/button/index.ts create mode 100644 preact-link/src/components/editor/ui/inline-menu/index.ts create mode 100644 preact-link/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 preact-link/src/main.tsx create mode 100644 preact-link/tsconfig.app.json create mode 100644 preact-link/tsconfig.json create mode 100644 preact-link/tsconfig.node.json create mode 100644 preact-link/vite.config.ts create mode 100644 preact-list-custom-checkbox/.gitignore create mode 100644 preact-list-custom-checkbox/README.md create mode 100644 preact-list-custom-checkbox/index.html create mode 100644 preact-list-custom-checkbox/package.json create mode 100644 preact-list-custom-checkbox/src/App.tsx create mode 100644 preact-list-custom-checkbox/src/app.css create mode 100644 preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css create mode 100644 preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx create mode 100644 preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts create mode 100644 preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts create mode 100644 preact-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts create mode 100644 preact-list-custom-checkbox/src/components/editor/ui/button/button.tsx create mode 100644 preact-list-custom-checkbox/src/components/editor/ui/button/index.ts create mode 100644 preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-list-custom-checkbox/src/main.tsx create mode 100644 preact-list-custom-checkbox/tsconfig.app.json create mode 100644 preact-list-custom-checkbox/tsconfig.json create mode 100644 preact-list-custom-checkbox/tsconfig.node.json create mode 100644 preact-list-custom-checkbox/vite.config.ts create mode 100644 preact-list/.gitignore create mode 100644 preact-list/README.md create mode 100644 preact-list/index.html create mode 100644 preact-list/package.json create mode 100644 preact-list/src/App.tsx create mode 100644 preact-list/src/app.css create mode 100644 preact-list/src/components/editor/examples/list/editor.tsx create mode 100644 preact-list/src/components/editor/examples/list/extension.ts create mode 100644 preact-list/src/components/editor/examples/list/index.ts create mode 100644 preact-list/src/components/editor/sample/sample-doc-list.ts create mode 100644 preact-list/src/components/editor/ui/button/button.tsx create mode 100644 preact-list/src/components/editor/ui/button/index.ts create mode 100644 preact-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-list/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-list/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-list/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-list/src/main.tsx create mode 100644 preact-list/tsconfig.app.json create mode 100644 preact-list/tsconfig.json create mode 100644 preact-list/tsconfig.node.json create mode 100644 preact-list/vite.config.ts create mode 100644 preact-loro/.gitignore create mode 100644 preact-loro/README.md create mode 100644 preact-loro/index.html create mode 100644 preact-loro/package.json create mode 100644 preact-loro/src/App.tsx create mode 100644 preact-loro/src/app.css create mode 100644 preact-loro/src/components/editor/examples/loro/editor-component.tsx create mode 100644 preact-loro/src/components/editor/examples/loro/editor.tsx create mode 100644 preact-loro/src/components/editor/examples/loro/extension.ts create mode 100644 preact-loro/src/components/editor/examples/loro/index.ts create mode 100644 preact-loro/src/components/editor/ui/button/button.tsx create mode 100644 preact-loro/src/components/editor/ui/button/index.ts create mode 100644 preact-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-loro/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-loro/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-loro/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-loro/src/main.tsx create mode 100644 preact-loro/tsconfig.app.json create mode 100644 preact-loro/tsconfig.json create mode 100644 preact-loro/tsconfig.node.json create mode 100644 preact-loro/vite.config.ts create mode 100644 preact-mark-rule/.gitignore create mode 100644 preact-mark-rule/README.md create mode 100644 preact-mark-rule/index.html create mode 100644 preact-mark-rule/package.json create mode 100644 preact-mark-rule/src/App.tsx create mode 100644 preact-mark-rule/src/app.css create mode 100644 preact-mark-rule/src/components/editor/examples/mark-rule/editor.tsx create mode 100644 preact-mark-rule/src/components/editor/examples/mark-rule/extension.ts create mode 100644 preact-mark-rule/src/components/editor/examples/mark-rule/index.ts create mode 100644 preact-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts create mode 100644 preact-mark-rule/src/main.tsx create mode 100644 preact-mark-rule/tsconfig.app.json create mode 100644 preact-mark-rule/tsconfig.json create mode 100644 preact-mark-rule/tsconfig.node.json create mode 100644 preact-mark-rule/vite.config.ts create mode 100644 preact-minimal/.gitignore create mode 100644 preact-minimal/README.md create mode 100644 preact-minimal/index.html create mode 100644 preact-minimal/package.json create mode 100644 preact-minimal/src/App.tsx create mode 100644 preact-minimal/src/app.css create mode 100644 preact-minimal/src/components/editor/examples/minimal/editor.tsx create mode 100644 preact-minimal/src/components/editor/examples/minimal/index.ts create mode 100644 preact-minimal/src/main.tsx create mode 100644 preact-minimal/tsconfig.app.json create mode 100644 preact-minimal/tsconfig.json create mode 100644 preact-minimal/tsconfig.node.json create mode 100644 preact-minimal/vite.config.ts create mode 100644 preact-placeholder/.gitignore create mode 100644 preact-placeholder/README.md create mode 100644 preact-placeholder/index.html create mode 100644 preact-placeholder/package.json create mode 100644 preact-placeholder/src/App.tsx create mode 100644 preact-placeholder/src/app.css create mode 100644 preact-placeholder/src/components/editor/examples/placeholder/editor.tsx create mode 100644 preact-placeholder/src/components/editor/examples/placeholder/extension.ts create mode 100644 preact-placeholder/src/components/editor/examples/placeholder/index.ts create mode 100644 preact-placeholder/src/main.tsx create mode 100644 preact-placeholder/tsconfig.app.json create mode 100644 preact-placeholder/tsconfig.json create mode 100644 preact-placeholder/tsconfig.node.json create mode 100644 preact-placeholder/vite.config.ts create mode 100644 preact-readonly/.gitignore create mode 100644 preact-readonly/README.md create mode 100644 preact-readonly/index.html create mode 100644 preact-readonly/package.json create mode 100644 preact-readonly/src/App.tsx create mode 100644 preact-readonly/src/app.css create mode 100644 preact-readonly/src/components/editor/examples/readonly/editor.tsx create mode 100644 preact-readonly/src/components/editor/examples/readonly/extension.ts create mode 100644 preact-readonly/src/components/editor/examples/readonly/index.ts create mode 100644 preact-readonly/src/components/editor/examples/readonly/toolbar.tsx create mode 100644 preact-readonly/src/components/editor/examples/readonly/use-readonly.ts create mode 100644 preact-readonly/src/components/editor/sample/sample-doc-readonly.ts create mode 100644 preact-readonly/src/components/editor/ui/button/button.tsx create mode 100644 preact-readonly/src/components/editor/ui/button/index.ts create mode 100644 preact-readonly/src/main.tsx create mode 100644 preact-readonly/tsconfig.app.json create mode 100644 preact-readonly/tsconfig.json create mode 100644 preact-readonly/tsconfig.node.json create mode 100644 preact-readonly/vite.config.ts create mode 100644 preact-rtl/.gitignore create mode 100644 preact-rtl/README.md create mode 100644 preact-rtl/index.html create mode 100644 preact-rtl/package.json create mode 100644 preact-rtl/src/App.tsx create mode 100644 preact-rtl/src/app.css create mode 100644 preact-rtl/src/components/editor/examples/rtl/editor.tsx create mode 100644 preact-rtl/src/components/editor/examples/rtl/index.ts create mode 100644 preact-rtl/src/components/editor/sample/sample-doc-rtl.ts create mode 100644 preact-rtl/src/components/editor/sample/sample-uploader.ts create mode 100644 preact-rtl/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 preact-rtl/src/components/editor/ui/block-handle/index.ts create mode 100644 preact-rtl/src/components/editor/ui/button/button.tsx create mode 100644 preact-rtl/src/components/editor/ui/button/index.ts create mode 100644 preact-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 preact-rtl/src/components/editor/ui/drop-indicator/index.ts create mode 100644 preact-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-rtl/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-rtl/src/components/editor/ui/inline-menu/index.ts create mode 100644 preact-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 preact-rtl/src/components/editor/ui/slash-menu/index.ts create mode 100644 preact-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 preact-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 preact-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 preact-rtl/src/components/editor/ui/table-handle/index.ts create mode 100644 preact-rtl/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 preact-rtl/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-rtl/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-rtl/src/main.tsx create mode 100644 preact-rtl/tsconfig.app.json create mode 100644 preact-rtl/tsconfig.json create mode 100644 preact-rtl/tsconfig.node.json create mode 100644 preact-rtl/vite.config.ts create mode 100644 preact-save-html/.gitignore create mode 100644 preact-save-html/README.md create mode 100644 preact-save-html/index.html create mode 100644 preact-save-html/package.json create mode 100644 preact-save-html/src/App.tsx create mode 100644 preact-save-html/src/app.css create mode 100644 preact-save-html/src/components/editor/examples/save-html/editor.tsx create mode 100644 preact-save-html/src/components/editor/examples/save-html/index.ts create mode 100644 preact-save-html/src/main.tsx create mode 100644 preact-save-html/tsconfig.app.json create mode 100644 preact-save-html/tsconfig.json create mode 100644 preact-save-html/tsconfig.node.json create mode 100644 preact-save-html/vite.config.ts create mode 100644 preact-save-json/.gitignore create mode 100644 preact-save-json/README.md create mode 100644 preact-save-json/index.html create mode 100644 preact-save-json/package.json create mode 100644 preact-save-json/src/App.tsx create mode 100644 preact-save-json/src/app.css create mode 100644 preact-save-json/src/components/editor/examples/save-json/editor.tsx create mode 100644 preact-save-json/src/components/editor/examples/save-json/index.ts create mode 100644 preact-save-json/src/main.tsx create mode 100644 preact-save-json/tsconfig.app.json create mode 100644 preact-save-json/tsconfig.json create mode 100644 preact-save-json/tsconfig.node.json create mode 100644 preact-save-json/vite.config.ts create mode 100644 preact-save-markdown/.gitignore create mode 100644 preact-save-markdown/README.md create mode 100644 preact-save-markdown/index.html create mode 100644 preact-save-markdown/package.json create mode 100644 preact-save-markdown/src/App.tsx create mode 100644 preact-save-markdown/src/app.css create mode 100644 preact-save-markdown/src/components/editor/examples/save-markdown/editor.tsx create mode 100644 preact-save-markdown/src/components/editor/examples/save-markdown/index.ts create mode 100644 preact-save-markdown/src/components/editor/examples/save-markdown/markdown.ts create mode 100644 preact-save-markdown/src/main.tsx create mode 100644 preact-save-markdown/tsconfig.app.json create mode 100644 preact-save-markdown/tsconfig.json create mode 100644 preact-save-markdown/tsconfig.node.json create mode 100644 preact-save-markdown/vite.config.ts create mode 100644 preact-search/.gitignore create mode 100644 preact-search/README.md create mode 100644 preact-search/index.html create mode 100644 preact-search/package.json create mode 100644 preact-search/src/App.tsx create mode 100644 preact-search/src/app.css create mode 100644 preact-search/src/components/editor/examples/search/editor.tsx create mode 100644 preact-search/src/components/editor/examples/search/extension.ts create mode 100644 preact-search/src/components/editor/examples/search/index.ts create mode 100644 preact-search/src/components/editor/sample/sample-doc-search.ts create mode 100644 preact-search/src/components/editor/ui/button/button.tsx create mode 100644 preact-search/src/components/editor/ui/button/index.ts create mode 100644 preact-search/src/components/editor/ui/search/index.ts create mode 100644 preact-search/src/components/editor/ui/search/search.tsx create mode 100644 preact-search/src/main.tsx create mode 100644 preact-search/tsconfig.app.json create mode 100644 preact-search/tsconfig.json create mode 100644 preact-search/tsconfig.node.json create mode 100644 preact-search/vite.config.ts create mode 100644 preact-slash-menu/.gitignore create mode 100644 preact-slash-menu/README.md create mode 100644 preact-slash-menu/index.html create mode 100644 preact-slash-menu/package.json create mode 100644 preact-slash-menu/src/App.tsx create mode 100644 preact-slash-menu/src/app.css create mode 100644 preact-slash-menu/src/components/editor/examples/slash-menu/editor.tsx create mode 100644 preact-slash-menu/src/components/editor/examples/slash-menu/extension.ts create mode 100644 preact-slash-menu/src/components/editor/examples/slash-menu/index.ts create mode 100644 preact-slash-menu/src/components/editor/ui/slash-menu/index.ts create mode 100644 preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 preact-slash-menu/src/main.tsx create mode 100644 preact-slash-menu/tsconfig.app.json create mode 100644 preact-slash-menu/tsconfig.json create mode 100644 preact-slash-menu/tsconfig.node.json create mode 100644 preact-slash-menu/vite.config.ts create mode 100644 preact-strike/.gitignore create mode 100644 preact-strike/README.md create mode 100644 preact-strike/index.html create mode 100644 preact-strike/package.json create mode 100644 preact-strike/src/App.tsx create mode 100644 preact-strike/src/app.css create mode 100644 preact-strike/src/components/editor/examples/strike/editor.tsx create mode 100644 preact-strike/src/components/editor/examples/strike/extension.ts create mode 100644 preact-strike/src/components/editor/examples/strike/index.ts create mode 100644 preact-strike/src/components/editor/examples/strike/toolbar.tsx create mode 100644 preact-strike/src/components/editor/sample/sample-doc-strike.ts create mode 100644 preact-strike/src/components/editor/ui/button/button.tsx create mode 100644 preact-strike/src/components/editor/ui/button/index.ts create mode 100644 preact-strike/src/main.tsx create mode 100644 preact-strike/tsconfig.app.json create mode 100644 preact-strike/tsconfig.json create mode 100644 preact-strike/tsconfig.node.json create mode 100644 preact-strike/vite.config.ts create mode 100644 preact-sub-sup/.gitignore create mode 100644 preact-sub-sup/README.md create mode 100644 preact-sub-sup/index.html create mode 100644 preact-sub-sup/package.json create mode 100644 preact-sub-sup/src/App.tsx create mode 100644 preact-sub-sup/src/app.css create mode 100644 preact-sub-sup/src/components/editor/examples/sub-sup/editor.tsx create mode 100644 preact-sub-sup/src/components/editor/examples/sub-sup/extension.ts create mode 100644 preact-sub-sup/src/components/editor/examples/sub-sup/index.ts create mode 100644 preact-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx create mode 100644 preact-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts create mode 100644 preact-sub-sup/src/components/editor/ui/button/button.tsx create mode 100644 preact-sub-sup/src/components/editor/ui/button/index.ts create mode 100644 preact-sub-sup/src/main.tsx create mode 100644 preact-sub-sup/tsconfig.app.json create mode 100644 preact-sub-sup/tsconfig.json create mode 100644 preact-sub-sup/tsconfig.node.json create mode 100644 preact-sub-sup/vite.config.ts create mode 100644 preact-table/.gitignore create mode 100644 preact-table/README.md create mode 100644 preact-table/index.html create mode 100644 preact-table/package.json create mode 100644 preact-table/src/App.tsx create mode 100644 preact-table/src/app.css create mode 100644 preact-table/src/components/editor/examples/table/editor.tsx create mode 100644 preact-table/src/components/editor/examples/table/extension.ts create mode 100644 preact-table/src/components/editor/examples/table/index.ts create mode 100644 preact-table/src/components/editor/sample/sample-doc-table.ts create mode 100644 preact-table/src/components/editor/ui/table-handle/index.ts create mode 100644 preact-table/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 preact-table/src/main.tsx create mode 100644 preact-table/tsconfig.app.json create mode 100644 preact-table/tsconfig.json create mode 100644 preact-table/tsconfig.node.json create mode 100644 preact-table/vite.config.ts create mode 100644 preact-text-align/.gitignore create mode 100644 preact-text-align/README.md create mode 100644 preact-text-align/index.html create mode 100644 preact-text-align/package.json create mode 100644 preact-text-align/src/App.tsx create mode 100644 preact-text-align/src/app.css create mode 100644 preact-text-align/src/components/editor/examples/text-align/editor.tsx create mode 100644 preact-text-align/src/components/editor/examples/text-align/extension.ts create mode 100644 preact-text-align/src/components/editor/examples/text-align/index.ts create mode 100644 preact-text-align/src/components/editor/examples/text-align/toolbar.tsx create mode 100644 preact-text-align/src/components/editor/sample/sample-doc-text-align.ts create mode 100644 preact-text-align/src/components/editor/ui/button/button.tsx create mode 100644 preact-text-align/src/components/editor/ui/button/index.ts create mode 100644 preact-text-align/src/main.tsx create mode 100644 preact-text-align/tsconfig.app.json create mode 100644 preact-text-align/tsconfig.json create mode 100644 preact-text-align/tsconfig.node.json create mode 100644 preact-text-align/vite.config.ts create mode 100644 preact-text-color/.gitignore create mode 100644 preact-text-color/README.md create mode 100644 preact-text-color/index.html create mode 100644 preact-text-color/package.json create mode 100644 preact-text-color/src/App.tsx create mode 100644 preact-text-color/src/app.css create mode 100644 preact-text-color/src/components/editor/examples/text-color/editor.tsx create mode 100644 preact-text-color/src/components/editor/examples/text-color/extension.ts create mode 100644 preact-text-color/src/components/editor/examples/text-color/index.ts create mode 100644 preact-text-color/src/components/editor/examples/text-color/inline-menu.tsx create mode 100644 preact-text-color/src/components/editor/sample/sample-doc-text-color.ts create mode 100644 preact-text-color/src/components/editor/ui/button/button.tsx create mode 100644 preact-text-color/src/components/editor/ui/button/index.ts create mode 100644 preact-text-color/src/main.tsx create mode 100644 preact-text-color/tsconfig.app.json create mode 100644 preact-text-color/tsconfig.json create mode 100644 preact-text-color/tsconfig.node.json create mode 100644 preact-text-color/vite.config.ts create mode 100644 preact-toolbar/.gitignore create mode 100644 preact-toolbar/README.md create mode 100644 preact-toolbar/index.html create mode 100644 preact-toolbar/package.json create mode 100644 preact-toolbar/src/App.tsx create mode 100644 preact-toolbar/src/app.css create mode 100644 preact-toolbar/src/components/editor/examples/toolbar/editor.tsx create mode 100644 preact-toolbar/src/components/editor/examples/toolbar/extension.ts create mode 100644 preact-toolbar/src/components/editor/examples/toolbar/index.ts create mode 100644 preact-toolbar/src/components/editor/sample/sample-uploader.ts create mode 100644 preact-toolbar/src/components/editor/ui/button/button.tsx create mode 100644 preact-toolbar/src/components/editor/ui/button/index.ts create mode 100644 preact-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-toolbar/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-toolbar/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-toolbar/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-toolbar/src/main.tsx create mode 100644 preact-toolbar/tsconfig.app.json create mode 100644 preact-toolbar/tsconfig.json create mode 100644 preact-toolbar/tsconfig.node.json create mode 100644 preact-toolbar/vite.config.ts create mode 100644 preact-typography/.gitignore create mode 100644 preact-typography/README.md create mode 100644 preact-typography/index.html create mode 100644 preact-typography/package.json create mode 100644 preact-typography/src/App.tsx create mode 100644 preact-typography/src/app.css create mode 100644 preact-typography/src/components/editor/examples/typography/editor.tsx create mode 100644 preact-typography/src/components/editor/examples/typography/extension.ts create mode 100644 preact-typography/src/components/editor/examples/typography/index.ts create mode 100644 preact-typography/src/components/editor/sample/katex.ts create mode 100644 preact-typography/src/components/editor/sample/sample-doc-typography.ts create mode 100644 preact-typography/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 preact-typography/src/components/editor/ui/block-handle/index.ts create mode 100644 preact-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 preact-typography/src/components/editor/ui/drop-indicator/index.ts create mode 100644 preact-typography/src/main.tsx create mode 100644 preact-typography/tsconfig.app.json create mode 100644 preact-typography/tsconfig.json create mode 100644 preact-typography/tsconfig.node.json create mode 100644 preact-typography/vite.config.ts create mode 100644 preact-underline/.gitignore create mode 100644 preact-underline/README.md create mode 100644 preact-underline/index.html create mode 100644 preact-underline/package.json create mode 100644 preact-underline/src/App.tsx create mode 100644 preact-underline/src/app.css create mode 100644 preact-underline/src/components/editor/examples/underline/editor.tsx create mode 100644 preact-underline/src/components/editor/examples/underline/extension.ts create mode 100644 preact-underline/src/components/editor/examples/underline/index.ts create mode 100644 preact-underline/src/components/editor/sample/sample-doc-underline.ts create mode 100644 preact-underline/src/components/editor/ui/button/button.tsx create mode 100644 preact-underline/src/components/editor/ui/button/index.ts create mode 100644 preact-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-underline/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-underline/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-underline/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-underline/src/main.tsx create mode 100644 preact-underline/tsconfig.app.json create mode 100644 preact-underline/tsconfig.json create mode 100644 preact-underline/tsconfig.node.json create mode 100644 preact-underline/vite.config.ts create mode 100644 preact-unmount/.gitignore create mode 100644 preact-unmount/README.md create mode 100644 preact-unmount/index.html create mode 100644 preact-unmount/package.json create mode 100644 preact-unmount/src/App.tsx create mode 100644 preact-unmount/src/app.css create mode 100644 preact-unmount/src/components/editor/examples/unmount/editor-component.tsx create mode 100644 preact-unmount/src/components/editor/examples/unmount/editor.tsx create mode 100644 preact-unmount/src/components/editor/examples/unmount/extension-component.tsx create mode 100644 preact-unmount/src/components/editor/examples/unmount/index.ts create mode 100644 preact-unmount/src/components/editor/ui/button/button.tsx create mode 100644 preact-unmount/src/components/editor/ui/button/index.ts create mode 100644 preact-unmount/src/components/editor/ui/inline-menu/index.ts create mode 100644 preact-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 preact-unmount/src/main.tsx create mode 100644 preact-unmount/tsconfig.app.json create mode 100644 preact-unmount/tsconfig.json create mode 100644 preact-unmount/tsconfig.node.json create mode 100644 preact-unmount/vite.config.ts create mode 100644 preact-user-menu-dynamic/.gitignore create mode 100644 preact-user-menu-dynamic/README.md create mode 100644 preact-user-menu-dynamic/index.html create mode 100644 preact-user-menu-dynamic/package.json create mode 100644 preact-user-menu-dynamic/src/App.tsx create mode 100644 preact-user-menu-dynamic/src/app.css create mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx create mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts create mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts create mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts create mode 100644 preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx create mode 100644 preact-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts create mode 100644 preact-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts create mode 100644 preact-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts create mode 100644 preact-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 preact-user-menu-dynamic/src/main.tsx create mode 100644 preact-user-menu-dynamic/tsconfig.app.json create mode 100644 preact-user-menu-dynamic/tsconfig.json create mode 100644 preact-user-menu-dynamic/tsconfig.node.json create mode 100644 preact-user-menu-dynamic/vite.config.ts create mode 100644 preact-user-menu/.gitignore create mode 100644 preact-user-menu/README.md create mode 100644 preact-user-menu/index.html create mode 100644 preact-user-menu/package.json create mode 100644 preact-user-menu/src/App.tsx create mode 100644 preact-user-menu/src/app.css create mode 100644 preact-user-menu/src/components/editor/examples/user-menu/editor.tsx create mode 100644 preact-user-menu/src/components/editor/examples/user-menu/extension.ts create mode 100644 preact-user-menu/src/components/editor/examples/user-menu/index.ts create mode 100644 preact-user-menu/src/components/editor/sample/sample-tag-data.ts create mode 100644 preact-user-menu/src/components/editor/sample/sample-user-data.ts create mode 100644 preact-user-menu/src/components/editor/ui/tag-menu/index.ts create mode 100644 preact-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx create mode 100644 preact-user-menu/src/components/editor/ui/user-menu/index.ts create mode 100644 preact-user-menu/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 preact-user-menu/src/main.tsx create mode 100644 preact-user-menu/tsconfig.app.json create mode 100644 preact-user-menu/tsconfig.json create mode 100644 preact-user-menu/tsconfig.node.json create mode 100644 preact-user-menu/vite.config.ts create mode 100644 preact-word-counter/.gitignore create mode 100644 preact-word-counter/README.md create mode 100644 preact-word-counter/index.html create mode 100644 preact-word-counter/package.json create mode 100644 preact-word-counter/src/App.tsx create mode 100644 preact-word-counter/src/app.css create mode 100644 preact-word-counter/src/components/editor/examples/word-counter/editor.tsx create mode 100644 preact-word-counter/src/components/editor/examples/word-counter/extension.ts create mode 100644 preact-word-counter/src/components/editor/examples/word-counter/index.ts create mode 100644 preact-word-counter/src/components/editor/sample/sample-doc-word-counter.ts create mode 100644 preact-word-counter/src/components/editor/ui/word-counter/index.ts create mode 100644 preact-word-counter/src/components/editor/ui/word-counter/word-counter.tsx create mode 100644 preact-word-counter/src/main.tsx create mode 100644 preact-word-counter/tsconfig.app.json create mode 100644 preact-word-counter/tsconfig.json create mode 100644 preact-word-counter/tsconfig.node.json create mode 100644 preact-word-counter/vite.config.ts create mode 100644 preact-yjs/.gitignore create mode 100644 preact-yjs/README.md create mode 100644 preact-yjs/index.html create mode 100644 preact-yjs/package.json create mode 100644 preact-yjs/src/App.tsx create mode 100644 preact-yjs/src/app.css create mode 100644 preact-yjs/src/components/editor/examples/yjs/editor-component.tsx create mode 100644 preact-yjs/src/components/editor/examples/yjs/editor.tsx create mode 100644 preact-yjs/src/components/editor/examples/yjs/extension.ts create mode 100644 preact-yjs/src/components/editor/examples/yjs/index.ts create mode 100644 preact-yjs/src/components/editor/ui/button/button.tsx create mode 100644 preact-yjs/src/components/editor/ui/button/index.ts create mode 100644 preact-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 preact-yjs/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 preact-yjs/src/components/editor/ui/toolbar/index.ts create mode 100644 preact-yjs/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 preact-yjs/src/main.tsx create mode 100644 preact-yjs/tsconfig.app.json create mode 100644 preact-yjs/tsconfig.json create mode 100644 preact-yjs/tsconfig.node.json create mode 100644 preact-yjs/vite.config.ts create mode 100644 react-block-handle/.gitignore create mode 100644 react-block-handle/README.md create mode 100644 react-block-handle/index.html create mode 100644 react-block-handle/package.json create mode 100644 react-block-handle/src/App.tsx create mode 100644 react-block-handle/src/app.css create mode 100644 react-block-handle/src/components/editor/examples/block-handle/editor.tsx create mode 100644 react-block-handle/src/components/editor/examples/block-handle/extension.ts create mode 100644 react-block-handle/src/components/editor/examples/block-handle/index.ts create mode 100644 react-block-handle/src/components/editor/sample/sample-doc-block-handle.ts create mode 100644 react-block-handle/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 react-block-handle/src/components/editor/ui/block-handle/index.ts create mode 100644 react-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 react-block-handle/src/components/editor/ui/code-block-view/index.ts create mode 100644 react-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 react-block-handle/src/components/editor/ui/drop-indicator/index.ts create mode 100644 react-block-handle/src/main.tsx create mode 100644 react-block-handle/tsconfig.app.json create mode 100644 react-block-handle/tsconfig.json create mode 100644 react-block-handle/tsconfig.node.json create mode 100644 react-block-handle/vite.config.ts create mode 100644 react-blockquote/.gitignore create mode 100644 react-blockquote/README.md create mode 100644 react-blockquote/index.html create mode 100644 react-blockquote/package.json create mode 100644 react-blockquote/src/App.tsx create mode 100644 react-blockquote/src/app.css create mode 100644 react-blockquote/src/components/editor/examples/blockquote/editor.tsx create mode 100644 react-blockquote/src/components/editor/examples/blockquote/extension.ts create mode 100644 react-blockquote/src/components/editor/examples/blockquote/index.ts create mode 100644 react-blockquote/src/components/editor/ui/button/button.tsx create mode 100644 react-blockquote/src/components/editor/ui/button/index.ts create mode 100644 react-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-blockquote/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-blockquote/src/components/editor/ui/toolbar/index.ts create mode 100644 react-blockquote/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-blockquote/src/main.tsx create mode 100644 react-blockquote/tsconfig.app.json create mode 100644 react-blockquote/tsconfig.json create mode 100644 react-blockquote/tsconfig.node.json create mode 100644 react-blockquote/vite.config.ts create mode 100644 react-bold/.gitignore create mode 100644 react-bold/README.md create mode 100644 react-bold/index.html create mode 100644 react-bold/package.json create mode 100644 react-bold/src/App.tsx create mode 100644 react-bold/src/app.css create mode 100644 react-bold/src/components/editor/examples/bold/editor.tsx create mode 100644 react-bold/src/components/editor/examples/bold/extension.ts create mode 100644 react-bold/src/components/editor/examples/bold/index.ts create mode 100644 react-bold/src/components/editor/sample/sample-doc-bold.ts create mode 100644 react-bold/src/components/editor/ui/button/button.tsx create mode 100644 react-bold/src/components/editor/ui/button/index.ts create mode 100644 react-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-bold/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-bold/src/components/editor/ui/toolbar/index.ts create mode 100644 react-bold/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-bold/src/main.tsx create mode 100644 react-bold/tsconfig.app.json create mode 100644 react-bold/tsconfig.json create mode 100644 react-bold/tsconfig.node.json create mode 100644 react-bold/vite.config.ts create mode 100644 react-change-tracking/.gitignore create mode 100644 react-change-tracking/README.md create mode 100644 react-change-tracking/index.html create mode 100644 react-change-tracking/package.json create mode 100644 react-change-tracking/src/App.tsx create mode 100644 react-change-tracking/src/app.css create mode 100644 react-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx create mode 100644 react-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx create mode 100644 react-change-tracking/src/components/editor/examples/change-tracking/editor.tsx create mode 100644 react-change-tracking/src/components/editor/examples/change-tracking/index.ts create mode 100644 react-change-tracking/src/main.tsx create mode 100644 react-change-tracking/tsconfig.app.json create mode 100644 react-change-tracking/tsconfig.json create mode 100644 react-change-tracking/tsconfig.node.json create mode 100644 react-change-tracking/vite.config.ts create mode 100644 react-code-block-themes/.gitignore create mode 100644 react-code-block-themes/README.md create mode 100644 react-code-block-themes/index.html create mode 100644 react-code-block-themes/package.json create mode 100644 react-code-block-themes/src/App.tsx create mode 100644 react-code-block-themes/src/app.css create mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx create mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts create mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/index.ts create mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx create mode 100644 react-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx create mode 100644 react-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 react-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 react-code-block-themes/src/components/editor/ui/code-block-view/index.ts create mode 100644 react-code-block-themes/src/main.tsx create mode 100644 react-code-block-themes/tsconfig.app.json create mode 100644 react-code-block-themes/tsconfig.json create mode 100644 react-code-block-themes/tsconfig.node.json create mode 100644 react-code-block-themes/vite.config.ts create mode 100644 react-code-block/.gitignore create mode 100644 react-code-block/README.md create mode 100644 react-code-block/index.html create mode 100644 react-code-block/package.json create mode 100644 react-code-block/src/App.tsx create mode 100644 react-code-block/src/app.css create mode 100644 react-code-block/src/components/editor/examples/code-block/editor.tsx create mode 100644 react-code-block/src/components/editor/examples/code-block/extension.ts create mode 100644 react-code-block/src/components/editor/examples/code-block/index.ts create mode 100644 react-code-block/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 react-code-block/src/components/editor/ui/button/button.tsx create mode 100644 react-code-block/src/components/editor/ui/button/index.ts create mode 100644 react-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 react-code-block/src/components/editor/ui/code-block-view/index.ts create mode 100644 react-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-code-block/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-code-block/src/components/editor/ui/toolbar/index.ts create mode 100644 react-code-block/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-code-block/src/main.tsx create mode 100644 react-code-block/tsconfig.app.json create mode 100644 react-code-block/tsconfig.json create mode 100644 react-code-block/tsconfig.node.json create mode 100644 react-code-block/vite.config.ts create mode 100644 react-code/.gitignore create mode 100644 react-code/README.md create mode 100644 react-code/index.html create mode 100644 react-code/package.json create mode 100644 react-code/src/App.tsx create mode 100644 react-code/src/app.css create mode 100644 react-code/src/components/editor/examples/code/editor.tsx create mode 100644 react-code/src/components/editor/examples/code/extension.ts create mode 100644 react-code/src/components/editor/examples/code/index.ts create mode 100644 react-code/src/components/editor/sample/sample-doc-code.ts create mode 100644 react-code/src/components/editor/ui/button/button.tsx create mode 100644 react-code/src/components/editor/ui/button/index.ts create mode 100644 react-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-code/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-code/src/components/editor/ui/toolbar/index.ts create mode 100644 react-code/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-code/src/main.tsx create mode 100644 react-code/tsconfig.app.json create mode 100644 react-code/tsconfig.json create mode 100644 react-code/tsconfig.node.json create mode 100644 react-code/vite.config.ts create mode 100644 react-drop-cursor/.gitignore create mode 100644 react-drop-cursor/README.md create mode 100644 react-drop-cursor/index.html create mode 100644 react-drop-cursor/package.json create mode 100644 react-drop-cursor/src/App.tsx create mode 100644 react-drop-cursor/src/app.css create mode 100644 react-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx create mode 100644 react-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts create mode 100644 react-drop-cursor/src/components/editor/examples/drop-cursor/index.ts create mode 100644 react-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts create mode 100644 react-drop-cursor/src/main.tsx create mode 100644 react-drop-cursor/tsconfig.app.json create mode 100644 react-drop-cursor/tsconfig.json create mode 100644 react-drop-cursor/tsconfig.node.json create mode 100644 react-drop-cursor/vite.config.ts create mode 100644 react-emoji-rules/.gitignore create mode 100644 react-emoji-rules/README.md create mode 100644 react-emoji-rules/index.html create mode 100644 react-emoji-rules/package.json create mode 100644 react-emoji-rules/src/App.tsx create mode 100644 react-emoji-rules/src/app.css create mode 100644 react-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx create mode 100644 react-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts create mode 100644 react-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts create mode 100644 react-emoji-rules/src/components/editor/examples/emoji-rules/index.ts create mode 100644 react-emoji-rules/src/main.tsx create mode 100644 react-emoji-rules/tsconfig.app.json create mode 100644 react-emoji-rules/tsconfig.json create mode 100644 react-emoji-rules/tsconfig.node.json create mode 100644 react-emoji-rules/vite.config.ts create mode 100644 react-full/.gitignore create mode 100644 react-full/README.md create mode 100644 react-full/index.html create mode 100644 react-full/package.json create mode 100644 react-full/src/App.tsx create mode 100644 react-full/src/app.css create mode 100644 react-full/src/components/editor/examples/full/editor.tsx create mode 100644 react-full/src/components/editor/examples/full/extension.ts create mode 100644 react-full/src/components/editor/examples/full/html.ts create mode 100644 react-full/src/components/editor/examples/full/index.ts create mode 100644 react-full/src/components/editor/sample/katex.ts create mode 100644 react-full/src/components/editor/sample/sample-doc-full.ts create mode 100644 react-full/src/components/editor/sample/sample-tag-data.ts create mode 100644 react-full/src/components/editor/sample/sample-uploader.ts create mode 100644 react-full/src/components/editor/sample/sample-user-data.ts create mode 100644 react-full/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 react-full/src/components/editor/ui/block-handle/index.ts create mode 100644 react-full/src/components/editor/ui/button/button.tsx create mode 100644 react-full/src/components/editor/ui/button/index.ts create mode 100644 react-full/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 react-full/src/components/editor/ui/code-block-view/index.ts create mode 100644 react-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 react-full/src/components/editor/ui/drop-indicator/index.ts create mode 100644 react-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-full/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-full/src/components/editor/ui/image-view/image-view.tsx create mode 100644 react-full/src/components/editor/ui/image-view/index.ts create mode 100644 react-full/src/components/editor/ui/inline-menu/index.ts create mode 100644 react-full/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 react-full/src/components/editor/ui/slash-menu/index.ts create mode 100644 react-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 react-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 react-full/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 react-full/src/components/editor/ui/table-handle/index.ts create mode 100644 react-full/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 react-full/src/components/editor/ui/tag-menu/index.ts create mode 100644 react-full/src/components/editor/ui/tag-menu/tag-menu.tsx create mode 100644 react-full/src/components/editor/ui/toolbar/index.ts create mode 100644 react-full/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-full/src/components/editor/ui/user-menu/index.ts create mode 100644 react-full/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 react-full/src/main.tsx create mode 100644 react-full/tsconfig.app.json create mode 100644 react-full/tsconfig.json create mode 100644 react-full/tsconfig.node.json create mode 100644 react-full/vite.config.ts create mode 100644 react-gap-cursor/.gitignore create mode 100644 react-gap-cursor/README.md create mode 100644 react-gap-cursor/index.html create mode 100644 react-gap-cursor/package.json create mode 100644 react-gap-cursor/src/App.tsx create mode 100644 react-gap-cursor/src/app.css create mode 100644 react-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx create mode 100644 react-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts create mode 100644 react-gap-cursor/src/components/editor/examples/gap-cursor/index.ts create mode 100644 react-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts create mode 100644 react-gap-cursor/src/main.tsx create mode 100644 react-gap-cursor/tsconfig.app.json create mode 100644 react-gap-cursor/tsconfig.json create mode 100644 react-gap-cursor/tsconfig.node.json create mode 100644 react-gap-cursor/vite.config.ts create mode 100644 react-hard-break/.gitignore create mode 100644 react-hard-break/README.md create mode 100644 react-hard-break/index.html create mode 100644 react-hard-break/package.json create mode 100644 react-hard-break/src/App.tsx create mode 100644 react-hard-break/src/app.css create mode 100644 react-hard-break/src/components/editor/examples/hard-break/editor.tsx create mode 100644 react-hard-break/src/components/editor/examples/hard-break/extension.ts create mode 100644 react-hard-break/src/components/editor/examples/hard-break/index.ts create mode 100644 react-hard-break/src/components/editor/examples/hard-break/toolbar.tsx create mode 100644 react-hard-break/src/components/editor/sample/sample-doc-hard-break.ts create mode 100644 react-hard-break/src/components/editor/ui/button/button.tsx create mode 100644 react-hard-break/src/components/editor/ui/button/index.ts create mode 100644 react-hard-break/src/main.tsx create mode 100644 react-hard-break/tsconfig.app.json create mode 100644 react-hard-break/tsconfig.json create mode 100644 react-hard-break/tsconfig.node.json create mode 100644 react-hard-break/vite.config.ts create mode 100644 react-heading/.gitignore create mode 100644 react-heading/README.md create mode 100644 react-heading/index.html create mode 100644 react-heading/package.json create mode 100644 react-heading/src/App.tsx create mode 100644 react-heading/src/app.css create mode 100644 react-heading/src/components/editor/examples/heading/editor.tsx create mode 100644 react-heading/src/components/editor/examples/heading/extension.ts create mode 100644 react-heading/src/components/editor/examples/heading/index.ts create mode 100644 react-heading/src/components/editor/sample/sample-doc-heading.ts create mode 100644 react-heading/src/components/editor/ui/button/button.tsx create mode 100644 react-heading/src/components/editor/ui/button/index.ts create mode 100644 react-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-heading/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-heading/src/components/editor/ui/toolbar/index.ts create mode 100644 react-heading/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-heading/src/main.tsx create mode 100644 react-heading/tsconfig.app.json create mode 100644 react-heading/tsconfig.json create mode 100644 react-heading/tsconfig.node.json create mode 100644 react-heading/vite.config.ts create mode 100644 react-highlight/.gitignore create mode 100644 react-highlight/README.md create mode 100644 react-highlight/index.html create mode 100644 react-highlight/package.json create mode 100644 react-highlight/src/App.tsx create mode 100644 react-highlight/src/app.css create mode 100644 react-highlight/src/components/editor/examples/highlight/editor.tsx create mode 100644 react-highlight/src/components/editor/examples/highlight/extension.ts create mode 100644 react-highlight/src/components/editor/examples/highlight/index.ts create mode 100644 react-highlight/src/components/editor/examples/highlight/toolbar.tsx create mode 100644 react-highlight/src/components/editor/sample/sample-doc-highlight.ts create mode 100644 react-highlight/src/components/editor/ui/button/button.tsx create mode 100644 react-highlight/src/components/editor/ui/button/index.ts create mode 100644 react-highlight/src/main.tsx create mode 100644 react-highlight/tsconfig.app.json create mode 100644 react-highlight/tsconfig.json create mode 100644 react-highlight/tsconfig.node.json create mode 100644 react-highlight/vite.config.ts create mode 100644 react-horizontal-rule/.gitignore create mode 100644 react-horizontal-rule/README.md create mode 100644 react-horizontal-rule/index.html create mode 100644 react-horizontal-rule/package.json create mode 100644 react-horizontal-rule/src/App.tsx create mode 100644 react-horizontal-rule/src/app.css create mode 100644 react-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx create mode 100644 react-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts create mode 100644 react-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts create mode 100644 react-horizontal-rule/src/components/editor/ui/button/button.tsx create mode 100644 react-horizontal-rule/src/components/editor/ui/button/index.ts create mode 100644 react-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-horizontal-rule/src/components/editor/ui/toolbar/index.ts create mode 100644 react-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-horizontal-rule/src/main.tsx create mode 100644 react-horizontal-rule/tsconfig.app.json create mode 100644 react-horizontal-rule/tsconfig.json create mode 100644 react-horizontal-rule/tsconfig.node.json create mode 100644 react-horizontal-rule/vite.config.ts create mode 100644 react-image-view/.gitignore create mode 100644 react-image-view/README.md create mode 100644 react-image-view/index.html create mode 100644 react-image-view/package.json create mode 100644 react-image-view/src/App.tsx create mode 100644 react-image-view/src/app.css create mode 100644 react-image-view/src/components/editor/examples/image-view/editor.tsx create mode 100644 react-image-view/src/components/editor/examples/image-view/extension.ts create mode 100644 react-image-view/src/components/editor/examples/image-view/index.ts create mode 100644 react-image-view/src/components/editor/sample/sample-doc-image.ts create mode 100644 react-image-view/src/components/editor/sample/sample-uploader.ts create mode 100644 react-image-view/src/components/editor/ui/image-view/image-view.tsx create mode 100644 react-image-view/src/components/editor/ui/image-view/index.ts create mode 100644 react-image-view/src/main.tsx create mode 100644 react-image-view/tsconfig.app.json create mode 100644 react-image-view/tsconfig.json create mode 100644 react-image-view/tsconfig.node.json create mode 100644 react-image-view/vite.config.ts create mode 100644 react-inline-menu/.gitignore create mode 100644 react-inline-menu/README.md create mode 100644 react-inline-menu/index.html create mode 100644 react-inline-menu/package.json create mode 100644 react-inline-menu/src/App.tsx create mode 100644 react-inline-menu/src/app.css create mode 100644 react-inline-menu/src/components/editor/examples/inline-menu/editor.tsx create mode 100644 react-inline-menu/src/components/editor/examples/inline-menu/extension.ts create mode 100644 react-inline-menu/src/components/editor/examples/inline-menu/index.ts create mode 100644 react-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts create mode 100644 react-inline-menu/src/components/editor/ui/button/button.tsx create mode 100644 react-inline-menu/src/components/editor/ui/button/index.ts create mode 100644 react-inline-menu/src/components/editor/ui/inline-menu/index.ts create mode 100644 react-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 react-inline-menu/src/main.tsx create mode 100644 react-inline-menu/tsconfig.app.json create mode 100644 react-inline-menu/tsconfig.json create mode 100644 react-inline-menu/tsconfig.node.json create mode 100644 react-inline-menu/vite.config.ts create mode 100644 react-italic/.gitignore create mode 100644 react-italic/README.md create mode 100644 react-italic/index.html create mode 100644 react-italic/package.json create mode 100644 react-italic/src/App.tsx create mode 100644 react-italic/src/app.css create mode 100644 react-italic/src/components/editor/examples/italic/editor.tsx create mode 100644 react-italic/src/components/editor/examples/italic/extension.ts create mode 100644 react-italic/src/components/editor/examples/italic/index.ts create mode 100644 react-italic/src/components/editor/sample/sample-doc-italic.ts create mode 100644 react-italic/src/components/editor/ui/button/button.tsx create mode 100644 react-italic/src/components/editor/ui/button/index.ts create mode 100644 react-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-italic/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-italic/src/components/editor/ui/toolbar/index.ts create mode 100644 react-italic/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-italic/src/main.tsx create mode 100644 react-italic/tsconfig.app.json create mode 100644 react-italic/tsconfig.json create mode 100644 react-italic/tsconfig.node.json create mode 100644 react-italic/vite.config.ts create mode 100644 react-katex/.gitignore create mode 100644 react-katex/README.md create mode 100644 react-katex/index.html create mode 100644 react-katex/package.json create mode 100644 react-katex/src/App.tsx create mode 100644 react-katex/src/app.css create mode 100644 react-katex/src/components/editor/examples/katex/editor.tsx create mode 100644 react-katex/src/components/editor/examples/katex/extension.ts create mode 100644 react-katex/src/components/editor/examples/katex/index.ts create mode 100644 react-katex/src/components/editor/sample/katex.ts create mode 100644 react-katex/src/components/editor/sample/sample-doc-tex.ts create mode 100644 react-katex/src/main.tsx create mode 100644 react-katex/tsconfig.app.json create mode 100644 react-katex/tsconfig.json create mode 100644 react-katex/tsconfig.node.json create mode 100644 react-katex/vite.config.ts create mode 100644 react-keymap/.gitignore create mode 100644 react-keymap/README.md create mode 100644 react-keymap/index.html create mode 100644 react-keymap/package.json create mode 100644 react-keymap/src/App.tsx create mode 100644 react-keymap/src/app.css create mode 100644 react-keymap/src/components/editor/examples/keymap/editor.tsx create mode 100644 react-keymap/src/components/editor/examples/keymap/extension.ts create mode 100644 react-keymap/src/components/editor/examples/keymap/index.ts create mode 100644 react-keymap/src/components/editor/examples/keymap/toolbar.tsx create mode 100644 react-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts create mode 100644 react-keymap/src/components/editor/ui/button/button.tsx create mode 100644 react-keymap/src/components/editor/ui/button/index.ts create mode 100644 react-keymap/src/main.tsx create mode 100644 react-keymap/tsconfig.app.json create mode 100644 react-keymap/tsconfig.json create mode 100644 react-keymap/tsconfig.node.json create mode 100644 react-keymap/vite.config.ts create mode 100644 react-link-mark-view/.gitignore create mode 100644 react-link-mark-view/README.md create mode 100644 react-link-mark-view/index.html create mode 100644 react-link-mark-view/package.json create mode 100644 react-link-mark-view/src/App.tsx create mode 100644 react-link-mark-view/src/app.css create mode 100644 react-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx create mode 100644 react-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts create mode 100644 react-link-mark-view/src/components/editor/examples/link-mark-view/index.ts create mode 100644 react-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx create mode 100644 react-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts create mode 100644 react-link-mark-view/src/main.tsx create mode 100644 react-link-mark-view/tsconfig.app.json create mode 100644 react-link-mark-view/tsconfig.json create mode 100644 react-link-mark-view/tsconfig.node.json create mode 100644 react-link-mark-view/vite.config.ts create mode 100644 react-link/.gitignore create mode 100644 react-link/README.md create mode 100644 react-link/index.html create mode 100644 react-link/package.json create mode 100644 react-link/src/App.tsx create mode 100644 react-link/src/app.css create mode 100644 react-link/src/components/editor/examples/link/editor.tsx create mode 100644 react-link/src/components/editor/examples/link/extension.ts create mode 100644 react-link/src/components/editor/examples/link/index.ts create mode 100644 react-link/src/components/editor/sample/sample-doc-link.ts create mode 100644 react-link/src/components/editor/ui/button/button.tsx create mode 100644 react-link/src/components/editor/ui/button/index.ts create mode 100644 react-link/src/components/editor/ui/inline-menu/index.ts create mode 100644 react-link/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 react-link/src/main.tsx create mode 100644 react-link/tsconfig.app.json create mode 100644 react-link/tsconfig.json create mode 100644 react-link/tsconfig.node.json create mode 100644 react-link/vite.config.ts create mode 100644 react-list-custom-checkbox/.gitignore create mode 100644 react-list-custom-checkbox/README.md create mode 100644 react-list-custom-checkbox/index.html create mode 100644 react-list-custom-checkbox/package.json create mode 100644 react-list-custom-checkbox/src/App.tsx create mode 100644 react-list-custom-checkbox/src/app.css create mode 100644 react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css create mode 100644 react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx create mode 100644 react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts create mode 100644 react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts create mode 100644 react-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts create mode 100644 react-list-custom-checkbox/src/components/editor/ui/button/button.tsx create mode 100644 react-list-custom-checkbox/src/components/editor/ui/button/index.ts create mode 100644 react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts create mode 100644 react-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-list-custom-checkbox/src/main.tsx create mode 100644 react-list-custom-checkbox/tsconfig.app.json create mode 100644 react-list-custom-checkbox/tsconfig.json create mode 100644 react-list-custom-checkbox/tsconfig.node.json create mode 100644 react-list-custom-checkbox/vite.config.ts create mode 100644 react-list/.gitignore create mode 100644 react-list/README.md create mode 100644 react-list/index.html create mode 100644 react-list/package.json create mode 100644 react-list/src/App.tsx create mode 100644 react-list/src/app.css create mode 100644 react-list/src/components/editor/examples/list/editor.tsx create mode 100644 react-list/src/components/editor/examples/list/extension.ts create mode 100644 react-list/src/components/editor/examples/list/index.ts create mode 100644 react-list/src/components/editor/sample/sample-doc-list.ts create mode 100644 react-list/src/components/editor/ui/button/button.tsx create mode 100644 react-list/src/components/editor/ui/button/index.ts create mode 100644 react-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-list/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-list/src/components/editor/ui/toolbar/index.ts create mode 100644 react-list/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-list/src/main.tsx create mode 100644 react-list/tsconfig.app.json create mode 100644 react-list/tsconfig.json create mode 100644 react-list/tsconfig.node.json create mode 100644 react-list/vite.config.ts create mode 100644 react-loro/.gitignore create mode 100644 react-loro/README.md create mode 100644 react-loro/index.html create mode 100644 react-loro/package.json create mode 100644 react-loro/src/App.tsx create mode 100644 react-loro/src/app.css create mode 100644 react-loro/src/components/editor/examples/loro/editor-component.tsx create mode 100644 react-loro/src/components/editor/examples/loro/editor.tsx create mode 100644 react-loro/src/components/editor/examples/loro/extension.ts create mode 100644 react-loro/src/components/editor/examples/loro/index.ts create mode 100644 react-loro/src/components/editor/ui/button/button.tsx create mode 100644 react-loro/src/components/editor/ui/button/index.ts create mode 100644 react-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-loro/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-loro/src/components/editor/ui/toolbar/index.ts create mode 100644 react-loro/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-loro/src/main.tsx create mode 100644 react-loro/tsconfig.app.json create mode 100644 react-loro/tsconfig.json create mode 100644 react-loro/tsconfig.node.json create mode 100644 react-loro/vite.config.ts create mode 100644 react-mark-rule/.gitignore create mode 100644 react-mark-rule/README.md create mode 100644 react-mark-rule/index.html create mode 100644 react-mark-rule/package.json create mode 100644 react-mark-rule/src/App.tsx create mode 100644 react-mark-rule/src/app.css create mode 100644 react-mark-rule/src/components/editor/examples/mark-rule/editor.tsx create mode 100644 react-mark-rule/src/components/editor/examples/mark-rule/extension.ts create mode 100644 react-mark-rule/src/components/editor/examples/mark-rule/index.ts create mode 100644 react-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts create mode 100644 react-mark-rule/src/main.tsx create mode 100644 react-mark-rule/tsconfig.app.json create mode 100644 react-mark-rule/tsconfig.json create mode 100644 react-mark-rule/tsconfig.node.json create mode 100644 react-mark-rule/vite.config.ts create mode 100644 react-minimal/.gitignore create mode 100644 react-minimal/README.md create mode 100644 react-minimal/index.html create mode 100644 react-minimal/package.json create mode 100644 react-minimal/src/App.tsx create mode 100644 react-minimal/src/app.css create mode 100644 react-minimal/src/components/editor/examples/minimal/editor.tsx create mode 100644 react-minimal/src/components/editor/examples/minimal/index.ts create mode 100644 react-minimal/src/main.tsx create mode 100644 react-minimal/tsconfig.app.json create mode 100644 react-minimal/tsconfig.json create mode 100644 react-minimal/tsconfig.node.json create mode 100644 react-minimal/vite.config.ts create mode 100644 react-page/.gitignore create mode 100644 react-page/README.md create mode 100644 react-page/index.html create mode 100644 react-page/package.json create mode 100644 react-page/src/App.tsx create mode 100644 react-page/src/app.css create mode 100644 react-page/src/components/editor/examples/page/editor.tsx create mode 100644 react-page/src/components/editor/examples/page/extension.ts create mode 100644 react-page/src/components/editor/examples/page/index.ts create mode 100644 react-page/src/components/editor/examples/page/paper-controller.tsx create mode 100644 react-page/src/components/editor/examples/page/zoom.css create mode 100644 react-page/src/components/editor/sample/sample-doc-page.ts create mode 100644 react-page/src/main.tsx create mode 100644 react-page/tsconfig.app.json create mode 100644 react-page/tsconfig.json create mode 100644 react-page/tsconfig.node.json create mode 100644 react-page/vite.config.ts create mode 100644 react-placeholder/.gitignore create mode 100644 react-placeholder/README.md create mode 100644 react-placeholder/index.html create mode 100644 react-placeholder/package.json create mode 100644 react-placeholder/src/App.tsx create mode 100644 react-placeholder/src/app.css create mode 100644 react-placeholder/src/components/editor/examples/placeholder/editor.tsx create mode 100644 react-placeholder/src/components/editor/examples/placeholder/extension.ts create mode 100644 react-placeholder/src/components/editor/examples/placeholder/index.ts create mode 100644 react-placeholder/src/main.tsx create mode 100644 react-placeholder/tsconfig.app.json create mode 100644 react-placeholder/tsconfig.json create mode 100644 react-placeholder/tsconfig.node.json create mode 100644 react-placeholder/vite.config.ts create mode 100644 react-readonly/.gitignore create mode 100644 react-readonly/README.md create mode 100644 react-readonly/index.html create mode 100644 react-readonly/package.json create mode 100644 react-readonly/src/App.tsx create mode 100644 react-readonly/src/app.css create mode 100644 react-readonly/src/components/editor/examples/readonly/editor.tsx create mode 100644 react-readonly/src/components/editor/examples/readonly/extension.ts create mode 100644 react-readonly/src/components/editor/examples/readonly/index.ts create mode 100644 react-readonly/src/components/editor/examples/readonly/toolbar.tsx create mode 100644 react-readonly/src/components/editor/examples/readonly/use-readonly.ts create mode 100644 react-readonly/src/components/editor/sample/sample-doc-readonly.ts create mode 100644 react-readonly/src/components/editor/ui/button/button.tsx create mode 100644 react-readonly/src/components/editor/ui/button/index.ts create mode 100644 react-readonly/src/main.tsx create mode 100644 react-readonly/tsconfig.app.json create mode 100644 react-readonly/tsconfig.json create mode 100644 react-readonly/tsconfig.node.json create mode 100644 react-readonly/vite.config.ts create mode 100644 react-rtl/.gitignore create mode 100644 react-rtl/README.md create mode 100644 react-rtl/index.html create mode 100644 react-rtl/package.json create mode 100644 react-rtl/src/App.tsx create mode 100644 react-rtl/src/app.css create mode 100644 react-rtl/src/components/editor/examples/rtl/editor.tsx create mode 100644 react-rtl/src/components/editor/examples/rtl/index.ts create mode 100644 react-rtl/src/components/editor/sample/sample-doc-rtl.ts create mode 100644 react-rtl/src/components/editor/sample/sample-uploader.ts create mode 100644 react-rtl/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 react-rtl/src/components/editor/ui/block-handle/index.ts create mode 100644 react-rtl/src/components/editor/ui/button/button.tsx create mode 100644 react-rtl/src/components/editor/ui/button/index.ts create mode 100644 react-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 react-rtl/src/components/editor/ui/drop-indicator/index.ts create mode 100644 react-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-rtl/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-rtl/src/components/editor/ui/inline-menu/index.ts create mode 100644 react-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 react-rtl/src/components/editor/ui/slash-menu/index.ts create mode 100644 react-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 react-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 react-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 react-rtl/src/components/editor/ui/table-handle/index.ts create mode 100644 react-rtl/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 react-rtl/src/components/editor/ui/toolbar/index.ts create mode 100644 react-rtl/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-rtl/src/main.tsx create mode 100644 react-rtl/tsconfig.app.json create mode 100644 react-rtl/tsconfig.json create mode 100644 react-rtl/tsconfig.node.json create mode 100644 react-rtl/vite.config.ts create mode 100644 react-save-html/.gitignore create mode 100644 react-save-html/README.md create mode 100644 react-save-html/index.html create mode 100644 react-save-html/package.json create mode 100644 react-save-html/src/App.tsx create mode 100644 react-save-html/src/app.css create mode 100644 react-save-html/src/components/editor/examples/save-html/editor.tsx create mode 100644 react-save-html/src/components/editor/examples/save-html/index.ts create mode 100644 react-save-html/src/main.tsx create mode 100644 react-save-html/tsconfig.app.json create mode 100644 react-save-html/tsconfig.json create mode 100644 react-save-html/tsconfig.node.json create mode 100644 react-save-html/vite.config.ts create mode 100644 react-save-json/.gitignore create mode 100644 react-save-json/README.md create mode 100644 react-save-json/index.html create mode 100644 react-save-json/package.json create mode 100644 react-save-json/src/App.tsx create mode 100644 react-save-json/src/app.css create mode 100644 react-save-json/src/components/editor/examples/save-json/editor.tsx create mode 100644 react-save-json/src/components/editor/examples/save-json/index.ts create mode 100644 react-save-json/src/main.tsx create mode 100644 react-save-json/tsconfig.app.json create mode 100644 react-save-json/tsconfig.json create mode 100644 react-save-json/tsconfig.node.json create mode 100644 react-save-json/vite.config.ts create mode 100644 react-save-markdown/.gitignore create mode 100644 react-save-markdown/README.md create mode 100644 react-save-markdown/index.html create mode 100644 react-save-markdown/package.json create mode 100644 react-save-markdown/src/App.tsx create mode 100644 react-save-markdown/src/app.css create mode 100644 react-save-markdown/src/components/editor/examples/save-markdown/editor.tsx create mode 100644 react-save-markdown/src/components/editor/examples/save-markdown/index.ts create mode 100644 react-save-markdown/src/components/editor/examples/save-markdown/markdown.ts create mode 100644 react-save-markdown/src/main.tsx create mode 100644 react-save-markdown/tsconfig.app.json create mode 100644 react-save-markdown/tsconfig.json create mode 100644 react-save-markdown/tsconfig.node.json create mode 100644 react-save-markdown/vite.config.ts create mode 100644 react-search/.gitignore create mode 100644 react-search/README.md create mode 100644 react-search/index.html create mode 100644 react-search/package.json create mode 100644 react-search/src/App.tsx create mode 100644 react-search/src/app.css create mode 100644 react-search/src/components/editor/examples/search/editor.tsx create mode 100644 react-search/src/components/editor/examples/search/extension.ts create mode 100644 react-search/src/components/editor/examples/search/index.ts create mode 100644 react-search/src/components/editor/sample/sample-doc-search.ts create mode 100644 react-search/src/components/editor/ui/button/button.tsx create mode 100644 react-search/src/components/editor/ui/button/index.ts create mode 100644 react-search/src/components/editor/ui/search/index.ts create mode 100644 react-search/src/components/editor/ui/search/search.tsx create mode 100644 react-search/src/main.tsx create mode 100644 react-search/tsconfig.app.json create mode 100644 react-search/tsconfig.json create mode 100644 react-search/tsconfig.node.json create mode 100644 react-search/vite.config.ts create mode 100644 react-slash-menu/.gitignore create mode 100644 react-slash-menu/README.md create mode 100644 react-slash-menu/index.html create mode 100644 react-slash-menu/package.json create mode 100644 react-slash-menu/src/App.tsx create mode 100644 react-slash-menu/src/app.css create mode 100644 react-slash-menu/src/components/editor/examples/slash-menu/editor.tsx create mode 100644 react-slash-menu/src/components/editor/examples/slash-menu/extension.ts create mode 100644 react-slash-menu/src/components/editor/examples/slash-menu/index.ts create mode 100644 react-slash-menu/src/components/editor/ui/slash-menu/index.ts create mode 100644 react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 react-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 react-slash-menu/src/main.tsx create mode 100644 react-slash-menu/tsconfig.app.json create mode 100644 react-slash-menu/tsconfig.json create mode 100644 react-slash-menu/tsconfig.node.json create mode 100644 react-slash-menu/vite.config.ts create mode 100644 react-strike/.gitignore create mode 100644 react-strike/README.md create mode 100644 react-strike/index.html create mode 100644 react-strike/package.json create mode 100644 react-strike/src/App.tsx create mode 100644 react-strike/src/app.css create mode 100644 react-strike/src/components/editor/examples/strike/editor.tsx create mode 100644 react-strike/src/components/editor/examples/strike/extension.ts create mode 100644 react-strike/src/components/editor/examples/strike/index.ts create mode 100644 react-strike/src/components/editor/examples/strike/toolbar.tsx create mode 100644 react-strike/src/components/editor/sample/sample-doc-strike.ts create mode 100644 react-strike/src/components/editor/ui/button/button.tsx create mode 100644 react-strike/src/components/editor/ui/button/index.ts create mode 100644 react-strike/src/main.tsx create mode 100644 react-strike/tsconfig.app.json create mode 100644 react-strike/tsconfig.json create mode 100644 react-strike/tsconfig.node.json create mode 100644 react-strike/vite.config.ts create mode 100644 react-sub-sup/.gitignore create mode 100644 react-sub-sup/README.md create mode 100644 react-sub-sup/index.html create mode 100644 react-sub-sup/package.json create mode 100644 react-sub-sup/src/App.tsx create mode 100644 react-sub-sup/src/app.css create mode 100644 react-sub-sup/src/components/editor/examples/sub-sup/editor.tsx create mode 100644 react-sub-sup/src/components/editor/examples/sub-sup/extension.ts create mode 100644 react-sub-sup/src/components/editor/examples/sub-sup/index.ts create mode 100644 react-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx create mode 100644 react-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts create mode 100644 react-sub-sup/src/components/editor/ui/button/button.tsx create mode 100644 react-sub-sup/src/components/editor/ui/button/index.ts create mode 100644 react-sub-sup/src/main.tsx create mode 100644 react-sub-sup/tsconfig.app.json create mode 100644 react-sub-sup/tsconfig.json create mode 100644 react-sub-sup/tsconfig.node.json create mode 100644 react-sub-sup/vite.config.ts create mode 100644 react-table/.gitignore create mode 100644 react-table/README.md create mode 100644 react-table/index.html create mode 100644 react-table/package.json create mode 100644 react-table/src/App.tsx create mode 100644 react-table/src/app.css create mode 100644 react-table/src/components/editor/examples/table/editor.tsx create mode 100644 react-table/src/components/editor/examples/table/extension.ts create mode 100644 react-table/src/components/editor/examples/table/index.ts create mode 100644 react-table/src/components/editor/sample/sample-doc-table.ts create mode 100644 react-table/src/components/editor/ui/table-handle/index.ts create mode 100644 react-table/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 react-table/src/main.tsx create mode 100644 react-table/tsconfig.app.json create mode 100644 react-table/tsconfig.json create mode 100644 react-table/tsconfig.node.json create mode 100644 react-table/vite.config.ts create mode 100644 react-text-align/.gitignore create mode 100644 react-text-align/README.md create mode 100644 react-text-align/index.html create mode 100644 react-text-align/package.json create mode 100644 react-text-align/src/App.tsx create mode 100644 react-text-align/src/app.css create mode 100644 react-text-align/src/components/editor/examples/text-align/editor.tsx create mode 100644 react-text-align/src/components/editor/examples/text-align/extension.ts create mode 100644 react-text-align/src/components/editor/examples/text-align/index.ts create mode 100644 react-text-align/src/components/editor/examples/text-align/toolbar.tsx create mode 100644 react-text-align/src/components/editor/sample/sample-doc-text-align.ts create mode 100644 react-text-align/src/components/editor/ui/button/button.tsx create mode 100644 react-text-align/src/components/editor/ui/button/index.ts create mode 100644 react-text-align/src/main.tsx create mode 100644 react-text-align/tsconfig.app.json create mode 100644 react-text-align/tsconfig.json create mode 100644 react-text-align/tsconfig.node.json create mode 100644 react-text-align/vite.config.ts create mode 100644 react-text-color/.gitignore create mode 100644 react-text-color/README.md create mode 100644 react-text-color/index.html create mode 100644 react-text-color/package.json create mode 100644 react-text-color/src/App.tsx create mode 100644 react-text-color/src/app.css create mode 100644 react-text-color/src/components/editor/examples/text-color/editor.tsx create mode 100644 react-text-color/src/components/editor/examples/text-color/extension.ts create mode 100644 react-text-color/src/components/editor/examples/text-color/index.ts create mode 100644 react-text-color/src/components/editor/examples/text-color/inline-menu.tsx create mode 100644 react-text-color/src/components/editor/sample/sample-doc-text-color.ts create mode 100644 react-text-color/src/components/editor/ui/button/button.tsx create mode 100644 react-text-color/src/components/editor/ui/button/index.ts create mode 100644 react-text-color/src/main.tsx create mode 100644 react-text-color/tsconfig.app.json create mode 100644 react-text-color/tsconfig.json create mode 100644 react-text-color/tsconfig.node.json create mode 100644 react-text-color/vite.config.ts create mode 100644 react-toolbar/.gitignore create mode 100644 react-toolbar/README.md create mode 100644 react-toolbar/index.html create mode 100644 react-toolbar/package.json create mode 100644 react-toolbar/src/App.tsx create mode 100644 react-toolbar/src/app.css create mode 100644 react-toolbar/src/components/editor/examples/toolbar/editor.tsx create mode 100644 react-toolbar/src/components/editor/examples/toolbar/extension.ts create mode 100644 react-toolbar/src/components/editor/examples/toolbar/index.ts create mode 100644 react-toolbar/src/components/editor/sample/sample-uploader.ts create mode 100644 react-toolbar/src/components/editor/ui/button/button.tsx create mode 100644 react-toolbar/src/components/editor/ui/button/index.ts create mode 100644 react-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-toolbar/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-toolbar/src/components/editor/ui/toolbar/index.ts create mode 100644 react-toolbar/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-toolbar/src/main.tsx create mode 100644 react-toolbar/tsconfig.app.json create mode 100644 react-toolbar/tsconfig.json create mode 100644 react-toolbar/tsconfig.node.json create mode 100644 react-toolbar/vite.config.ts create mode 100644 react-tweet/.gitignore create mode 100644 react-tweet/README.md create mode 100644 react-tweet/index.html create mode 100644 react-tweet/package.json create mode 100644 react-tweet/src/App.tsx create mode 100644 react-tweet/src/app.css create mode 100644 react-tweet/src/components/editor/examples/tweet/editor.tsx create mode 100644 react-tweet/src/components/editor/examples/tweet/extension.ts create mode 100644 react-tweet/src/components/editor/examples/tweet/index.ts create mode 100644 react-tweet/src/components/editor/examples/tweet/method-select.tsx create mode 100644 react-tweet/src/components/editor/examples/tweet/tweet-view.tsx create mode 100644 react-tweet/src/components/editor/sample/sample-doc-tweet.ts create mode 100644 react-tweet/src/main.tsx create mode 100644 react-tweet/tsconfig.app.json create mode 100644 react-tweet/tsconfig.json create mode 100644 react-tweet/tsconfig.node.json create mode 100644 react-tweet/vite.config.ts create mode 100644 react-typography/.gitignore create mode 100644 react-typography/README.md create mode 100644 react-typography/index.html create mode 100644 react-typography/package.json create mode 100644 react-typography/src/App.tsx create mode 100644 react-typography/src/app.css create mode 100644 react-typography/src/components/editor/examples/typography/editor.tsx create mode 100644 react-typography/src/components/editor/examples/typography/extension.ts create mode 100644 react-typography/src/components/editor/examples/typography/index.ts create mode 100644 react-typography/src/components/editor/sample/katex.ts create mode 100644 react-typography/src/components/editor/sample/sample-doc-typography.ts create mode 100644 react-typography/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 react-typography/src/components/editor/ui/block-handle/index.ts create mode 100644 react-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 react-typography/src/components/editor/ui/drop-indicator/index.ts create mode 100644 react-typography/src/main.tsx create mode 100644 react-typography/tsconfig.app.json create mode 100644 react-typography/tsconfig.json create mode 100644 react-typography/tsconfig.node.json create mode 100644 react-typography/vite.config.ts create mode 100644 react-underline/.gitignore create mode 100644 react-underline/README.md create mode 100644 react-underline/index.html create mode 100644 react-underline/package.json create mode 100644 react-underline/src/App.tsx create mode 100644 react-underline/src/app.css create mode 100644 react-underline/src/components/editor/examples/underline/editor.tsx create mode 100644 react-underline/src/components/editor/examples/underline/extension.ts create mode 100644 react-underline/src/components/editor/examples/underline/index.ts create mode 100644 react-underline/src/components/editor/sample/sample-doc-underline.ts create mode 100644 react-underline/src/components/editor/ui/button/button.tsx create mode 100644 react-underline/src/components/editor/ui/button/index.ts create mode 100644 react-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-underline/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-underline/src/components/editor/ui/toolbar/index.ts create mode 100644 react-underline/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-underline/src/main.tsx create mode 100644 react-underline/tsconfig.app.json create mode 100644 react-underline/tsconfig.json create mode 100644 react-underline/tsconfig.node.json create mode 100644 react-underline/vite.config.ts create mode 100644 react-unmount/.gitignore create mode 100644 react-unmount/README.md create mode 100644 react-unmount/index.html create mode 100644 react-unmount/package.json create mode 100644 react-unmount/src/App.tsx create mode 100644 react-unmount/src/app.css create mode 100644 react-unmount/src/components/editor/examples/unmount/editor-component.tsx create mode 100644 react-unmount/src/components/editor/examples/unmount/editor.tsx create mode 100644 react-unmount/src/components/editor/examples/unmount/extension-component.tsx create mode 100644 react-unmount/src/components/editor/examples/unmount/index.ts create mode 100644 react-unmount/src/components/editor/ui/button/button.tsx create mode 100644 react-unmount/src/components/editor/ui/button/index.ts create mode 100644 react-unmount/src/components/editor/ui/inline-menu/index.ts create mode 100644 react-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 react-unmount/src/main.tsx create mode 100644 react-unmount/tsconfig.app.json create mode 100644 react-unmount/tsconfig.json create mode 100644 react-unmount/tsconfig.node.json create mode 100644 react-unmount/vite.config.ts create mode 100644 react-user-menu-dynamic/.gitignore create mode 100644 react-user-menu-dynamic/README.md create mode 100644 react-user-menu-dynamic/index.html create mode 100644 react-user-menu-dynamic/package.json create mode 100644 react-user-menu-dynamic/src/App.tsx create mode 100644 react-user-menu-dynamic/src/app.css create mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx create mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts create mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts create mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts create mode 100644 react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx create mode 100644 react-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts create mode 100644 react-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts create mode 100644 react-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts create mode 100644 react-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 react-user-menu-dynamic/src/main.tsx create mode 100644 react-user-menu-dynamic/tsconfig.app.json create mode 100644 react-user-menu-dynamic/tsconfig.json create mode 100644 react-user-menu-dynamic/tsconfig.node.json create mode 100644 react-user-menu-dynamic/vite.config.ts create mode 100644 react-user-menu/.gitignore create mode 100644 react-user-menu/README.md create mode 100644 react-user-menu/index.html create mode 100644 react-user-menu/package.json create mode 100644 react-user-menu/src/App.tsx create mode 100644 react-user-menu/src/app.css create mode 100644 react-user-menu/src/components/editor/examples/user-menu/editor.tsx create mode 100644 react-user-menu/src/components/editor/examples/user-menu/extension.ts create mode 100644 react-user-menu/src/components/editor/examples/user-menu/index.ts create mode 100644 react-user-menu/src/components/editor/sample/sample-tag-data.ts create mode 100644 react-user-menu/src/components/editor/sample/sample-user-data.ts create mode 100644 react-user-menu/src/components/editor/ui/tag-menu/index.ts create mode 100644 react-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx create mode 100644 react-user-menu/src/components/editor/ui/user-menu/index.ts create mode 100644 react-user-menu/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 react-user-menu/src/main.tsx create mode 100644 react-user-menu/tsconfig.app.json create mode 100644 react-user-menu/tsconfig.json create mode 100644 react-user-menu/tsconfig.node.json create mode 100644 react-user-menu/vite.config.ts create mode 100644 react-word-counter/.gitignore create mode 100644 react-word-counter/README.md create mode 100644 react-word-counter/index.html create mode 100644 react-word-counter/package.json create mode 100644 react-word-counter/src/App.tsx create mode 100644 react-word-counter/src/app.css create mode 100644 react-word-counter/src/components/editor/examples/word-counter/editor.tsx create mode 100644 react-word-counter/src/components/editor/examples/word-counter/extension.ts create mode 100644 react-word-counter/src/components/editor/examples/word-counter/index.ts create mode 100644 react-word-counter/src/components/editor/sample/sample-doc-word-counter.ts create mode 100644 react-word-counter/src/components/editor/ui/word-counter/index.ts create mode 100644 react-word-counter/src/components/editor/ui/word-counter/word-counter.tsx create mode 100644 react-word-counter/src/main.tsx create mode 100644 react-word-counter/tsconfig.app.json create mode 100644 react-word-counter/tsconfig.json create mode 100644 react-word-counter/tsconfig.node.json create mode 100644 react-word-counter/vite.config.ts create mode 100644 react-yjs/.gitignore create mode 100644 react-yjs/README.md create mode 100644 react-yjs/index.html create mode 100644 react-yjs/package.json create mode 100644 react-yjs/src/App.tsx create mode 100644 react-yjs/src/app.css create mode 100644 react-yjs/src/components/editor/examples/yjs/editor-component.tsx create mode 100644 react-yjs/src/components/editor/examples/yjs/editor.tsx create mode 100644 react-yjs/src/components/editor/examples/yjs/extension.ts create mode 100644 react-yjs/src/components/editor/examples/yjs/index.ts create mode 100644 react-yjs/src/components/editor/ui/button/button.tsx create mode 100644 react-yjs/src/components/editor/ui/button/index.ts create mode 100644 react-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 react-yjs/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 react-yjs/src/components/editor/ui/toolbar/index.ts create mode 100644 react-yjs/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 react-yjs/src/main.tsx create mode 100644 react-yjs/tsconfig.app.json create mode 100644 react-yjs/tsconfig.json create mode 100644 react-yjs/tsconfig.node.json create mode 100644 react-yjs/vite.config.ts create mode 100644 solid-block-handle/.gitignore create mode 100644 solid-block-handle/README.md create mode 100644 solid-block-handle/index.html create mode 100644 solid-block-handle/package.json create mode 100644 solid-block-handle/src/App.tsx create mode 100644 solid-block-handle/src/app.css create mode 100644 solid-block-handle/src/components/editor/examples/block-handle/editor.tsx create mode 100644 solid-block-handle/src/components/editor/examples/block-handle/extension.ts create mode 100644 solid-block-handle/src/components/editor/examples/block-handle/index.ts create mode 100644 solid-block-handle/src/components/editor/sample/sample-doc-block-handle.ts create mode 100644 solid-block-handle/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 solid-block-handle/src/components/editor/ui/block-handle/index.ts create mode 100644 solid-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 solid-block-handle/src/components/editor/ui/code-block-view/index.ts create mode 100644 solid-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 solid-block-handle/src/components/editor/ui/drop-indicator/index.ts create mode 100644 solid-block-handle/src/index.tsx create mode 100644 solid-block-handle/tsconfig.app.json create mode 100644 solid-block-handle/tsconfig.json create mode 100644 solid-block-handle/tsconfig.node.json create mode 100644 solid-block-handle/vite.config.ts create mode 100644 solid-blockquote/.gitignore create mode 100644 solid-blockquote/README.md create mode 100644 solid-blockquote/index.html create mode 100644 solid-blockquote/package.json create mode 100644 solid-blockquote/src/App.tsx create mode 100644 solid-blockquote/src/app.css create mode 100644 solid-blockquote/src/components/editor/examples/blockquote/editor.tsx create mode 100644 solid-blockquote/src/components/editor/examples/blockquote/extension.ts create mode 100644 solid-blockquote/src/components/editor/examples/blockquote/index.ts create mode 100644 solid-blockquote/src/components/editor/ui/button/button.tsx create mode 100644 solid-blockquote/src/components/editor/ui/button/index.ts create mode 100644 solid-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-blockquote/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-blockquote/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-blockquote/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-blockquote/src/index.tsx create mode 100644 solid-blockquote/tsconfig.app.json create mode 100644 solid-blockquote/tsconfig.json create mode 100644 solid-blockquote/tsconfig.node.json create mode 100644 solid-blockquote/vite.config.ts create mode 100644 solid-bold/.gitignore create mode 100644 solid-bold/README.md create mode 100644 solid-bold/index.html create mode 100644 solid-bold/package.json create mode 100644 solid-bold/src/App.tsx create mode 100644 solid-bold/src/app.css create mode 100644 solid-bold/src/components/editor/examples/bold/editor.tsx create mode 100644 solid-bold/src/components/editor/examples/bold/extension.ts create mode 100644 solid-bold/src/components/editor/examples/bold/index.ts create mode 100644 solid-bold/src/components/editor/sample/sample-doc-bold.ts create mode 100644 solid-bold/src/components/editor/ui/button/button.tsx create mode 100644 solid-bold/src/components/editor/ui/button/index.ts create mode 100644 solid-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-bold/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-bold/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-bold/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-bold/src/index.tsx create mode 100644 solid-bold/tsconfig.app.json create mode 100644 solid-bold/tsconfig.json create mode 100644 solid-bold/tsconfig.node.json create mode 100644 solid-bold/vite.config.ts create mode 100644 solid-change-tracking/.gitignore create mode 100644 solid-change-tracking/README.md create mode 100644 solid-change-tracking/index.html create mode 100644 solid-change-tracking/package.json create mode 100644 solid-change-tracking/src/App.tsx create mode 100644 solid-change-tracking/src/app.css create mode 100644 solid-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx create mode 100644 solid-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx create mode 100644 solid-change-tracking/src/components/editor/examples/change-tracking/editor.tsx create mode 100644 solid-change-tracking/src/components/editor/examples/change-tracking/index.ts create mode 100644 solid-change-tracking/src/index.tsx create mode 100644 solid-change-tracking/tsconfig.app.json create mode 100644 solid-change-tracking/tsconfig.json create mode 100644 solid-change-tracking/tsconfig.node.json create mode 100644 solid-change-tracking/vite.config.ts create mode 100644 solid-code-block-themes/.gitignore create mode 100644 solid-code-block-themes/README.md create mode 100644 solid-code-block-themes/index.html create mode 100644 solid-code-block-themes/package.json create mode 100644 solid-code-block-themes/src/App.tsx create mode 100644 solid-code-block-themes/src/app.css create mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx create mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts create mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/index.ts create mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx create mode 100644 solid-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx create mode 100644 solid-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 solid-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 solid-code-block-themes/src/components/editor/ui/code-block-view/index.ts create mode 100644 solid-code-block-themes/src/index.tsx create mode 100644 solid-code-block-themes/tsconfig.app.json create mode 100644 solid-code-block-themes/tsconfig.json create mode 100644 solid-code-block-themes/tsconfig.node.json create mode 100644 solid-code-block-themes/vite.config.ts create mode 100644 solid-code-block/.gitignore create mode 100644 solid-code-block/README.md create mode 100644 solid-code-block/index.html create mode 100644 solid-code-block/package.json create mode 100644 solid-code-block/src/App.tsx create mode 100644 solid-code-block/src/app.css create mode 100644 solid-code-block/src/components/editor/examples/code-block/editor.tsx create mode 100644 solid-code-block/src/components/editor/examples/code-block/extension.ts create mode 100644 solid-code-block/src/components/editor/examples/code-block/index.ts create mode 100644 solid-code-block/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 solid-code-block/src/components/editor/ui/button/button.tsx create mode 100644 solid-code-block/src/components/editor/ui/button/index.ts create mode 100644 solid-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 solid-code-block/src/components/editor/ui/code-block-view/index.ts create mode 100644 solid-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-code-block/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-code-block/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-code-block/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-code-block/src/index.tsx create mode 100644 solid-code-block/tsconfig.app.json create mode 100644 solid-code-block/tsconfig.json create mode 100644 solid-code-block/tsconfig.node.json create mode 100644 solid-code-block/vite.config.ts create mode 100644 solid-code/.gitignore create mode 100644 solid-code/README.md create mode 100644 solid-code/index.html create mode 100644 solid-code/package.json create mode 100644 solid-code/src/App.tsx create mode 100644 solid-code/src/app.css create mode 100644 solid-code/src/components/editor/examples/code/editor.tsx create mode 100644 solid-code/src/components/editor/examples/code/extension.ts create mode 100644 solid-code/src/components/editor/examples/code/index.ts create mode 100644 solid-code/src/components/editor/sample/sample-doc-code.ts create mode 100644 solid-code/src/components/editor/ui/button/button.tsx create mode 100644 solid-code/src/components/editor/ui/button/index.ts create mode 100644 solid-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-code/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-code/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-code/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-code/src/index.tsx create mode 100644 solid-code/tsconfig.app.json create mode 100644 solid-code/tsconfig.json create mode 100644 solid-code/tsconfig.node.json create mode 100644 solid-code/vite.config.ts create mode 100644 solid-drop-cursor/.gitignore create mode 100644 solid-drop-cursor/README.md create mode 100644 solid-drop-cursor/index.html create mode 100644 solid-drop-cursor/package.json create mode 100644 solid-drop-cursor/src/App.tsx create mode 100644 solid-drop-cursor/src/app.css create mode 100644 solid-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx create mode 100644 solid-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts create mode 100644 solid-drop-cursor/src/components/editor/examples/drop-cursor/index.ts create mode 100644 solid-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts create mode 100644 solid-drop-cursor/src/index.tsx create mode 100644 solid-drop-cursor/tsconfig.app.json create mode 100644 solid-drop-cursor/tsconfig.json create mode 100644 solid-drop-cursor/tsconfig.node.json create mode 100644 solid-drop-cursor/vite.config.ts create mode 100644 solid-emoji-rules/.gitignore create mode 100644 solid-emoji-rules/README.md create mode 100644 solid-emoji-rules/index.html create mode 100644 solid-emoji-rules/package.json create mode 100644 solid-emoji-rules/src/App.tsx create mode 100644 solid-emoji-rules/src/app.css create mode 100644 solid-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx create mode 100644 solid-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts create mode 100644 solid-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts create mode 100644 solid-emoji-rules/src/components/editor/examples/emoji-rules/index.ts create mode 100644 solid-emoji-rules/src/index.tsx create mode 100644 solid-emoji-rules/tsconfig.app.json create mode 100644 solid-emoji-rules/tsconfig.json create mode 100644 solid-emoji-rules/tsconfig.node.json create mode 100644 solid-emoji-rules/vite.config.ts create mode 100644 solid-full/.gitignore create mode 100644 solid-full/README.md create mode 100644 solid-full/index.html create mode 100644 solid-full/package.json create mode 100644 solid-full/src/App.tsx create mode 100644 solid-full/src/app.css create mode 100644 solid-full/src/components/editor/examples/full/editor.tsx create mode 100644 solid-full/src/components/editor/examples/full/extension.ts create mode 100644 solid-full/src/components/editor/examples/full/index.ts create mode 100644 solid-full/src/components/editor/sample/katex.ts create mode 100644 solid-full/src/components/editor/sample/sample-doc-full.ts create mode 100644 solid-full/src/components/editor/sample/sample-tag-data.ts create mode 100644 solid-full/src/components/editor/sample/sample-uploader.ts create mode 100644 solid-full/src/components/editor/sample/sample-user-data.ts create mode 100644 solid-full/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 solid-full/src/components/editor/ui/block-handle/index.ts create mode 100644 solid-full/src/components/editor/ui/button/button.tsx create mode 100644 solid-full/src/components/editor/ui/button/index.ts create mode 100644 solid-full/src/components/editor/ui/code-block-view/code-block-view.tsx create mode 100644 solid-full/src/components/editor/ui/code-block-view/index.ts create mode 100644 solid-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 solid-full/src/components/editor/ui/drop-indicator/index.ts create mode 100644 solid-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-full/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-full/src/components/editor/ui/image-view/image-view.tsx create mode 100644 solid-full/src/components/editor/ui/image-view/index.ts create mode 100644 solid-full/src/components/editor/ui/inline-menu/index.ts create mode 100644 solid-full/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 solid-full/src/components/editor/ui/slash-menu/index.ts create mode 100644 solid-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 solid-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 solid-full/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 solid-full/src/components/editor/ui/table-handle/index.ts create mode 100644 solid-full/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 solid-full/src/components/editor/ui/tag-menu/index.ts create mode 100644 solid-full/src/components/editor/ui/tag-menu/tag-menu.tsx create mode 100644 solid-full/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-full/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-full/src/components/editor/ui/user-menu/index.ts create mode 100644 solid-full/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 solid-full/src/index.tsx create mode 100644 solid-full/tsconfig.app.json create mode 100644 solid-full/tsconfig.json create mode 100644 solid-full/tsconfig.node.json create mode 100644 solid-full/vite.config.ts create mode 100644 solid-gap-cursor/.gitignore create mode 100644 solid-gap-cursor/README.md create mode 100644 solid-gap-cursor/index.html create mode 100644 solid-gap-cursor/package.json create mode 100644 solid-gap-cursor/src/App.tsx create mode 100644 solid-gap-cursor/src/app.css create mode 100644 solid-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx create mode 100644 solid-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts create mode 100644 solid-gap-cursor/src/components/editor/examples/gap-cursor/index.ts create mode 100644 solid-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts create mode 100644 solid-gap-cursor/src/index.tsx create mode 100644 solid-gap-cursor/tsconfig.app.json create mode 100644 solid-gap-cursor/tsconfig.json create mode 100644 solid-gap-cursor/tsconfig.node.json create mode 100644 solid-gap-cursor/vite.config.ts create mode 100644 solid-hard-break/.gitignore create mode 100644 solid-hard-break/README.md create mode 100644 solid-hard-break/index.html create mode 100644 solid-hard-break/package.json create mode 100644 solid-hard-break/src/App.tsx create mode 100644 solid-hard-break/src/app.css create mode 100644 solid-hard-break/src/components/editor/examples/hard-break/editor.tsx create mode 100644 solid-hard-break/src/components/editor/examples/hard-break/extension.ts create mode 100644 solid-hard-break/src/components/editor/examples/hard-break/index.ts create mode 100644 solid-hard-break/src/components/editor/examples/hard-break/toolbar.tsx create mode 100644 solid-hard-break/src/components/editor/sample/sample-doc-hard-break.ts create mode 100644 solid-hard-break/src/components/editor/ui/button/button.tsx create mode 100644 solid-hard-break/src/components/editor/ui/button/index.ts create mode 100644 solid-hard-break/src/index.tsx create mode 100644 solid-hard-break/tsconfig.app.json create mode 100644 solid-hard-break/tsconfig.json create mode 100644 solid-hard-break/tsconfig.node.json create mode 100644 solid-hard-break/vite.config.ts create mode 100644 solid-heading/.gitignore create mode 100644 solid-heading/README.md create mode 100644 solid-heading/index.html create mode 100644 solid-heading/package.json create mode 100644 solid-heading/src/App.tsx create mode 100644 solid-heading/src/app.css create mode 100644 solid-heading/src/components/editor/examples/heading/editor.tsx create mode 100644 solid-heading/src/components/editor/examples/heading/extension.ts create mode 100644 solid-heading/src/components/editor/examples/heading/index.ts create mode 100644 solid-heading/src/components/editor/sample/sample-doc-heading.ts create mode 100644 solid-heading/src/components/editor/ui/button/button.tsx create mode 100644 solid-heading/src/components/editor/ui/button/index.ts create mode 100644 solid-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-heading/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-heading/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-heading/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-heading/src/index.tsx create mode 100644 solid-heading/tsconfig.app.json create mode 100644 solid-heading/tsconfig.json create mode 100644 solid-heading/tsconfig.node.json create mode 100644 solid-heading/vite.config.ts create mode 100644 solid-highlight/.gitignore create mode 100644 solid-highlight/README.md create mode 100644 solid-highlight/index.html create mode 100644 solid-highlight/package.json create mode 100644 solid-highlight/src/App.tsx create mode 100644 solid-highlight/src/app.css create mode 100644 solid-highlight/src/components/editor/examples/highlight/editor.tsx create mode 100644 solid-highlight/src/components/editor/examples/highlight/extension.ts create mode 100644 solid-highlight/src/components/editor/examples/highlight/index.ts create mode 100644 solid-highlight/src/components/editor/examples/highlight/toolbar.tsx create mode 100644 solid-highlight/src/components/editor/sample/sample-doc-highlight.ts create mode 100644 solid-highlight/src/components/editor/ui/button/button.tsx create mode 100644 solid-highlight/src/components/editor/ui/button/index.ts create mode 100644 solid-highlight/src/index.tsx create mode 100644 solid-highlight/tsconfig.app.json create mode 100644 solid-highlight/tsconfig.json create mode 100644 solid-highlight/tsconfig.node.json create mode 100644 solid-highlight/vite.config.ts create mode 100644 solid-horizontal-rule/.gitignore create mode 100644 solid-horizontal-rule/README.md create mode 100644 solid-horizontal-rule/index.html create mode 100644 solid-horizontal-rule/package.json create mode 100644 solid-horizontal-rule/src/App.tsx create mode 100644 solid-horizontal-rule/src/app.css create mode 100644 solid-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx create mode 100644 solid-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts create mode 100644 solid-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts create mode 100644 solid-horizontal-rule/src/components/editor/ui/button/button.tsx create mode 100644 solid-horizontal-rule/src/components/editor/ui/button/index.ts create mode 100644 solid-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-horizontal-rule/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-horizontal-rule/src/index.tsx create mode 100644 solid-horizontal-rule/tsconfig.app.json create mode 100644 solid-horizontal-rule/tsconfig.json create mode 100644 solid-horizontal-rule/tsconfig.node.json create mode 100644 solid-horizontal-rule/vite.config.ts create mode 100644 solid-image-view/.gitignore create mode 100644 solid-image-view/README.md create mode 100644 solid-image-view/index.html create mode 100644 solid-image-view/package.json create mode 100644 solid-image-view/src/App.tsx create mode 100644 solid-image-view/src/app.css create mode 100644 solid-image-view/src/components/editor/examples/image-view/editor.tsx create mode 100644 solid-image-view/src/components/editor/examples/image-view/extension.ts create mode 100644 solid-image-view/src/components/editor/examples/image-view/index.ts create mode 100644 solid-image-view/src/components/editor/sample/sample-doc-image.ts create mode 100644 solid-image-view/src/components/editor/sample/sample-uploader.ts create mode 100644 solid-image-view/src/components/editor/ui/image-view/image-view.tsx create mode 100644 solid-image-view/src/components/editor/ui/image-view/index.ts create mode 100644 solid-image-view/src/index.tsx create mode 100644 solid-image-view/tsconfig.app.json create mode 100644 solid-image-view/tsconfig.json create mode 100644 solid-image-view/tsconfig.node.json create mode 100644 solid-image-view/vite.config.ts create mode 100644 solid-inline-menu/.gitignore create mode 100644 solid-inline-menu/README.md create mode 100644 solid-inline-menu/index.html create mode 100644 solid-inline-menu/package.json create mode 100644 solid-inline-menu/src/App.tsx create mode 100644 solid-inline-menu/src/app.css create mode 100644 solid-inline-menu/src/components/editor/examples/inline-menu/editor.tsx create mode 100644 solid-inline-menu/src/components/editor/examples/inline-menu/extension.ts create mode 100644 solid-inline-menu/src/components/editor/examples/inline-menu/index.ts create mode 100644 solid-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts create mode 100644 solid-inline-menu/src/components/editor/ui/button/button.tsx create mode 100644 solid-inline-menu/src/components/editor/ui/button/index.ts create mode 100644 solid-inline-menu/src/components/editor/ui/inline-menu/index.ts create mode 100644 solid-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 solid-inline-menu/src/index.tsx create mode 100644 solid-inline-menu/tsconfig.app.json create mode 100644 solid-inline-menu/tsconfig.json create mode 100644 solid-inline-menu/tsconfig.node.json create mode 100644 solid-inline-menu/vite.config.ts create mode 100644 solid-italic/.gitignore create mode 100644 solid-italic/README.md create mode 100644 solid-italic/index.html create mode 100644 solid-italic/package.json create mode 100644 solid-italic/src/App.tsx create mode 100644 solid-italic/src/app.css create mode 100644 solid-italic/src/components/editor/examples/italic/editor.tsx create mode 100644 solid-italic/src/components/editor/examples/italic/extension.ts create mode 100644 solid-italic/src/components/editor/examples/italic/index.ts create mode 100644 solid-italic/src/components/editor/sample/sample-doc-italic.ts create mode 100644 solid-italic/src/components/editor/ui/button/button.tsx create mode 100644 solid-italic/src/components/editor/ui/button/index.ts create mode 100644 solid-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-italic/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-italic/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-italic/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-italic/src/index.tsx create mode 100644 solid-italic/tsconfig.app.json create mode 100644 solid-italic/tsconfig.json create mode 100644 solid-italic/tsconfig.node.json create mode 100644 solid-italic/vite.config.ts create mode 100644 solid-katex/.gitignore create mode 100644 solid-katex/README.md create mode 100644 solid-katex/index.html create mode 100644 solid-katex/package.json create mode 100644 solid-katex/src/App.tsx create mode 100644 solid-katex/src/app.css create mode 100644 solid-katex/src/components/editor/examples/katex/editor.tsx create mode 100644 solid-katex/src/components/editor/examples/katex/extension.ts create mode 100644 solid-katex/src/components/editor/examples/katex/index.ts create mode 100644 solid-katex/src/components/editor/sample/katex.ts create mode 100644 solid-katex/src/components/editor/sample/sample-doc-tex.ts create mode 100644 solid-katex/src/index.tsx create mode 100644 solid-katex/tsconfig.app.json create mode 100644 solid-katex/tsconfig.json create mode 100644 solid-katex/tsconfig.node.json create mode 100644 solid-katex/vite.config.ts create mode 100644 solid-keymap/.gitignore create mode 100644 solid-keymap/README.md create mode 100644 solid-keymap/index.html create mode 100644 solid-keymap/package.json create mode 100644 solid-keymap/src/App.tsx create mode 100644 solid-keymap/src/app.css create mode 100644 solid-keymap/src/components/editor/examples/keymap/editor.tsx create mode 100644 solid-keymap/src/components/editor/examples/keymap/extension.ts create mode 100644 solid-keymap/src/components/editor/examples/keymap/index.ts create mode 100644 solid-keymap/src/components/editor/examples/keymap/toolbar.tsx create mode 100644 solid-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts create mode 100644 solid-keymap/src/components/editor/ui/button/button.tsx create mode 100644 solid-keymap/src/components/editor/ui/button/index.ts create mode 100644 solid-keymap/src/index.tsx create mode 100644 solid-keymap/tsconfig.app.json create mode 100644 solid-keymap/tsconfig.json create mode 100644 solid-keymap/tsconfig.node.json create mode 100644 solid-keymap/vite.config.ts create mode 100644 solid-link-mark-view/.gitignore create mode 100644 solid-link-mark-view/README.md create mode 100644 solid-link-mark-view/index.html create mode 100644 solid-link-mark-view/package.json create mode 100644 solid-link-mark-view/src/App.tsx create mode 100644 solid-link-mark-view/src/app.css create mode 100644 solid-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx create mode 100644 solid-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts create mode 100644 solid-link-mark-view/src/components/editor/examples/link-mark-view/index.ts create mode 100644 solid-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx create mode 100644 solid-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts create mode 100644 solid-link-mark-view/src/index.tsx create mode 100644 solid-link-mark-view/tsconfig.app.json create mode 100644 solid-link-mark-view/tsconfig.json create mode 100644 solid-link-mark-view/tsconfig.node.json create mode 100644 solid-link-mark-view/vite.config.ts create mode 100644 solid-link/.gitignore create mode 100644 solid-link/README.md create mode 100644 solid-link/index.html create mode 100644 solid-link/package.json create mode 100644 solid-link/src/App.tsx create mode 100644 solid-link/src/app.css create mode 100644 solid-link/src/components/editor/examples/link/editor.tsx create mode 100644 solid-link/src/components/editor/examples/link/extension.ts create mode 100644 solid-link/src/components/editor/examples/link/index.ts create mode 100644 solid-link/src/components/editor/sample/sample-doc-link.ts create mode 100644 solid-link/src/components/editor/ui/button/button.tsx create mode 100644 solid-link/src/components/editor/ui/button/index.ts create mode 100644 solid-link/src/components/editor/ui/inline-menu/index.ts create mode 100644 solid-link/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 solid-link/src/index.tsx create mode 100644 solid-link/tsconfig.app.json create mode 100644 solid-link/tsconfig.json create mode 100644 solid-link/tsconfig.node.json create mode 100644 solid-link/vite.config.ts create mode 100644 solid-list-custom-checkbox/.gitignore create mode 100644 solid-list-custom-checkbox/README.md create mode 100644 solid-list-custom-checkbox/index.html create mode 100644 solid-list-custom-checkbox/package.json create mode 100644 solid-list-custom-checkbox/src/App.tsx create mode 100644 solid-list-custom-checkbox/src/app.css create mode 100644 solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css create mode 100644 solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx create mode 100644 solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts create mode 100644 solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts create mode 100644 solid-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts create mode 100644 solid-list-custom-checkbox/src/components/editor/ui/button/button.tsx create mode 100644 solid-list-custom-checkbox/src/components/editor/ui/button/index.ts create mode 100644 solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-list-custom-checkbox/src/index.tsx create mode 100644 solid-list-custom-checkbox/tsconfig.app.json create mode 100644 solid-list-custom-checkbox/tsconfig.json create mode 100644 solid-list-custom-checkbox/tsconfig.node.json create mode 100644 solid-list-custom-checkbox/vite.config.ts create mode 100644 solid-list/.gitignore create mode 100644 solid-list/README.md create mode 100644 solid-list/index.html create mode 100644 solid-list/package.json create mode 100644 solid-list/src/App.tsx create mode 100644 solid-list/src/app.css create mode 100644 solid-list/src/components/editor/examples/list/editor.tsx create mode 100644 solid-list/src/components/editor/examples/list/extension.ts create mode 100644 solid-list/src/components/editor/examples/list/index.ts create mode 100644 solid-list/src/components/editor/sample/sample-doc-list.ts create mode 100644 solid-list/src/components/editor/ui/button/button.tsx create mode 100644 solid-list/src/components/editor/ui/button/index.ts create mode 100644 solid-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-list/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-list/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-list/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-list/src/index.tsx create mode 100644 solid-list/tsconfig.app.json create mode 100644 solid-list/tsconfig.json create mode 100644 solid-list/tsconfig.node.json create mode 100644 solid-list/vite.config.ts create mode 100644 solid-loro/.gitignore create mode 100644 solid-loro/README.md create mode 100644 solid-loro/index.html create mode 100644 solid-loro/package.json create mode 100644 solid-loro/src/App.tsx create mode 100644 solid-loro/src/app.css create mode 100644 solid-loro/src/components/editor/examples/loro/editor-component.tsx create mode 100644 solid-loro/src/components/editor/examples/loro/editor.tsx create mode 100644 solid-loro/src/components/editor/examples/loro/extension.ts create mode 100644 solid-loro/src/components/editor/examples/loro/index.ts create mode 100644 solid-loro/src/components/editor/ui/button/button.tsx create mode 100644 solid-loro/src/components/editor/ui/button/index.ts create mode 100644 solid-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-loro/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-loro/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-loro/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-loro/src/index.tsx create mode 100644 solid-loro/tsconfig.app.json create mode 100644 solid-loro/tsconfig.json create mode 100644 solid-loro/tsconfig.node.json create mode 100644 solid-loro/vite.config.ts create mode 100644 solid-mark-rule/.gitignore create mode 100644 solid-mark-rule/README.md create mode 100644 solid-mark-rule/index.html create mode 100644 solid-mark-rule/package.json create mode 100644 solid-mark-rule/src/App.tsx create mode 100644 solid-mark-rule/src/app.css create mode 100644 solid-mark-rule/src/components/editor/examples/mark-rule/editor.tsx create mode 100644 solid-mark-rule/src/components/editor/examples/mark-rule/extension.ts create mode 100644 solid-mark-rule/src/components/editor/examples/mark-rule/index.ts create mode 100644 solid-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts create mode 100644 solid-mark-rule/src/index.tsx create mode 100644 solid-mark-rule/tsconfig.app.json create mode 100644 solid-mark-rule/tsconfig.json create mode 100644 solid-mark-rule/tsconfig.node.json create mode 100644 solid-mark-rule/vite.config.ts create mode 100644 solid-minimal/.gitignore create mode 100644 solid-minimal/README.md create mode 100644 solid-minimal/index.html create mode 100644 solid-minimal/package.json create mode 100644 solid-minimal/src/App.tsx create mode 100644 solid-minimal/src/app.css create mode 100644 solid-minimal/src/components/editor/examples/minimal/editor.tsx create mode 100644 solid-minimal/src/components/editor/examples/minimal/index.ts create mode 100644 solid-minimal/src/index.tsx create mode 100644 solid-minimal/tsconfig.app.json create mode 100644 solid-minimal/tsconfig.json create mode 100644 solid-minimal/tsconfig.node.json create mode 100644 solid-minimal/vite.config.ts create mode 100644 solid-placeholder/.gitignore create mode 100644 solid-placeholder/README.md create mode 100644 solid-placeholder/index.html create mode 100644 solid-placeholder/package.json create mode 100644 solid-placeholder/src/App.tsx create mode 100644 solid-placeholder/src/app.css create mode 100644 solid-placeholder/src/components/editor/examples/placeholder/editor.tsx create mode 100644 solid-placeholder/src/components/editor/examples/placeholder/extension.ts create mode 100644 solid-placeholder/src/components/editor/examples/placeholder/index.ts create mode 100644 solid-placeholder/src/index.tsx create mode 100644 solid-placeholder/tsconfig.app.json create mode 100644 solid-placeholder/tsconfig.json create mode 100644 solid-placeholder/tsconfig.node.json create mode 100644 solid-placeholder/vite.config.ts create mode 100644 solid-readonly/.gitignore create mode 100644 solid-readonly/README.md create mode 100644 solid-readonly/index.html create mode 100644 solid-readonly/package.json create mode 100644 solid-readonly/src/App.tsx create mode 100644 solid-readonly/src/app.css create mode 100644 solid-readonly/src/components/editor/examples/readonly/editor.tsx create mode 100644 solid-readonly/src/components/editor/examples/readonly/extension.ts create mode 100644 solid-readonly/src/components/editor/examples/readonly/index.ts create mode 100644 solid-readonly/src/components/editor/examples/readonly/toolbar.tsx create mode 100644 solid-readonly/src/components/editor/examples/readonly/use-readonly.ts create mode 100644 solid-readonly/src/components/editor/sample/sample-doc-readonly.ts create mode 100644 solid-readonly/src/components/editor/ui/button/button.tsx create mode 100644 solid-readonly/src/components/editor/ui/button/index.ts create mode 100644 solid-readonly/src/index.tsx create mode 100644 solid-readonly/tsconfig.app.json create mode 100644 solid-readonly/tsconfig.json create mode 100644 solid-readonly/tsconfig.node.json create mode 100644 solid-readonly/vite.config.ts create mode 100644 solid-rtl/.gitignore create mode 100644 solid-rtl/README.md create mode 100644 solid-rtl/index.html create mode 100644 solid-rtl/package.json create mode 100644 solid-rtl/src/App.tsx create mode 100644 solid-rtl/src/app.css create mode 100644 solid-rtl/src/components/editor/examples/rtl/editor.tsx create mode 100644 solid-rtl/src/components/editor/examples/rtl/index.ts create mode 100644 solid-rtl/src/components/editor/sample/sample-doc-rtl.ts create mode 100644 solid-rtl/src/components/editor/sample/sample-uploader.ts create mode 100644 solid-rtl/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 solid-rtl/src/components/editor/ui/block-handle/index.ts create mode 100644 solid-rtl/src/components/editor/ui/button/button.tsx create mode 100644 solid-rtl/src/components/editor/ui/button/index.ts create mode 100644 solid-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 solid-rtl/src/components/editor/ui/drop-indicator/index.ts create mode 100644 solid-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-rtl/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-rtl/src/components/editor/ui/inline-menu/index.ts create mode 100644 solid-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 solid-rtl/src/components/editor/ui/slash-menu/index.ts create mode 100644 solid-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 solid-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 solid-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 solid-rtl/src/components/editor/ui/table-handle/index.ts create mode 100644 solid-rtl/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 solid-rtl/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-rtl/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-rtl/src/index.tsx create mode 100644 solid-rtl/tsconfig.app.json create mode 100644 solid-rtl/tsconfig.json create mode 100644 solid-rtl/tsconfig.node.json create mode 100644 solid-rtl/vite.config.ts create mode 100644 solid-save-html/.gitignore create mode 100644 solid-save-html/README.md create mode 100644 solid-save-html/index.html create mode 100644 solid-save-html/package.json create mode 100644 solid-save-html/src/App.tsx create mode 100644 solid-save-html/src/app.css create mode 100644 solid-save-html/src/components/editor/examples/save-html/editor.tsx create mode 100644 solid-save-html/src/components/editor/examples/save-html/index.ts create mode 100644 solid-save-html/src/index.tsx create mode 100644 solid-save-html/tsconfig.app.json create mode 100644 solid-save-html/tsconfig.json create mode 100644 solid-save-html/tsconfig.node.json create mode 100644 solid-save-html/vite.config.ts create mode 100644 solid-save-json/.gitignore create mode 100644 solid-save-json/README.md create mode 100644 solid-save-json/index.html create mode 100644 solid-save-json/package.json create mode 100644 solid-save-json/src/App.tsx create mode 100644 solid-save-json/src/app.css create mode 100644 solid-save-json/src/components/editor/examples/save-json/editor.tsx create mode 100644 solid-save-json/src/components/editor/examples/save-json/index.ts create mode 100644 solid-save-json/src/index.tsx create mode 100644 solid-save-json/tsconfig.app.json create mode 100644 solid-save-json/tsconfig.json create mode 100644 solid-save-json/tsconfig.node.json create mode 100644 solid-save-json/vite.config.ts create mode 100644 solid-save-markdown/.gitignore create mode 100644 solid-save-markdown/README.md create mode 100644 solid-save-markdown/index.html create mode 100644 solid-save-markdown/package.json create mode 100644 solid-save-markdown/src/App.tsx create mode 100644 solid-save-markdown/src/app.css create mode 100644 solid-save-markdown/src/components/editor/examples/save-markdown/editor.tsx create mode 100644 solid-save-markdown/src/components/editor/examples/save-markdown/index.ts create mode 100644 solid-save-markdown/src/components/editor/examples/save-markdown/markdown.ts create mode 100644 solid-save-markdown/src/index.tsx create mode 100644 solid-save-markdown/tsconfig.app.json create mode 100644 solid-save-markdown/tsconfig.json create mode 100644 solid-save-markdown/tsconfig.node.json create mode 100644 solid-save-markdown/vite.config.ts create mode 100644 solid-search/.gitignore create mode 100644 solid-search/README.md create mode 100644 solid-search/index.html create mode 100644 solid-search/package.json create mode 100644 solid-search/src/App.tsx create mode 100644 solid-search/src/app.css create mode 100644 solid-search/src/components/editor/examples/search/editor.tsx create mode 100644 solid-search/src/components/editor/examples/search/extension.ts create mode 100644 solid-search/src/components/editor/examples/search/index.ts create mode 100644 solid-search/src/components/editor/sample/sample-doc-search.ts create mode 100644 solid-search/src/components/editor/ui/button/button.tsx create mode 100644 solid-search/src/components/editor/ui/button/index.ts create mode 100644 solid-search/src/components/editor/ui/search/index.ts create mode 100644 solid-search/src/components/editor/ui/search/search.tsx create mode 100644 solid-search/src/index.tsx create mode 100644 solid-search/tsconfig.app.json create mode 100644 solid-search/tsconfig.json create mode 100644 solid-search/tsconfig.node.json create mode 100644 solid-search/vite.config.ts create mode 100644 solid-slash-menu/.gitignore create mode 100644 solid-slash-menu/README.md create mode 100644 solid-slash-menu/index.html create mode 100644 solid-slash-menu/package.json create mode 100644 solid-slash-menu/src/App.tsx create mode 100644 solid-slash-menu/src/app.css create mode 100644 solid-slash-menu/src/components/editor/examples/slash-menu/editor.tsx create mode 100644 solid-slash-menu/src/components/editor/examples/slash-menu/extension.ts create mode 100644 solid-slash-menu/src/components/editor/examples/slash-menu/index.ts create mode 100644 solid-slash-menu/src/components/editor/ui/slash-menu/index.ts create mode 100644 solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx create mode 100644 solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx create mode 100644 solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx create mode 100644 solid-slash-menu/src/index.tsx create mode 100644 solid-slash-menu/tsconfig.app.json create mode 100644 solid-slash-menu/tsconfig.json create mode 100644 solid-slash-menu/tsconfig.node.json create mode 100644 solid-slash-menu/vite.config.ts create mode 100644 solid-strike/.gitignore create mode 100644 solid-strike/README.md create mode 100644 solid-strike/index.html create mode 100644 solid-strike/package.json create mode 100644 solid-strike/src/App.tsx create mode 100644 solid-strike/src/app.css create mode 100644 solid-strike/src/components/editor/examples/strike/editor.tsx create mode 100644 solid-strike/src/components/editor/examples/strike/extension.ts create mode 100644 solid-strike/src/components/editor/examples/strike/index.ts create mode 100644 solid-strike/src/components/editor/examples/strike/toolbar.tsx create mode 100644 solid-strike/src/components/editor/sample/sample-doc-strike.ts create mode 100644 solid-strike/src/components/editor/ui/button/button.tsx create mode 100644 solid-strike/src/components/editor/ui/button/index.ts create mode 100644 solid-strike/src/index.tsx create mode 100644 solid-strike/tsconfig.app.json create mode 100644 solid-strike/tsconfig.json create mode 100644 solid-strike/tsconfig.node.json create mode 100644 solid-strike/vite.config.ts create mode 100644 solid-sub-sup/.gitignore create mode 100644 solid-sub-sup/README.md create mode 100644 solid-sub-sup/index.html create mode 100644 solid-sub-sup/package.json create mode 100644 solid-sub-sup/src/App.tsx create mode 100644 solid-sub-sup/src/app.css create mode 100644 solid-sub-sup/src/components/editor/examples/sub-sup/editor.tsx create mode 100644 solid-sub-sup/src/components/editor/examples/sub-sup/extension.ts create mode 100644 solid-sub-sup/src/components/editor/examples/sub-sup/index.ts create mode 100644 solid-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx create mode 100644 solid-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts create mode 100644 solid-sub-sup/src/components/editor/ui/button/button.tsx create mode 100644 solid-sub-sup/src/components/editor/ui/button/index.ts create mode 100644 solid-sub-sup/src/index.tsx create mode 100644 solid-sub-sup/tsconfig.app.json create mode 100644 solid-sub-sup/tsconfig.json create mode 100644 solid-sub-sup/tsconfig.node.json create mode 100644 solid-sub-sup/vite.config.ts create mode 100644 solid-table/.gitignore create mode 100644 solid-table/README.md create mode 100644 solid-table/index.html create mode 100644 solid-table/package.json create mode 100644 solid-table/src/App.tsx create mode 100644 solid-table/src/app.css create mode 100644 solid-table/src/components/editor/examples/table/editor.tsx create mode 100644 solid-table/src/components/editor/examples/table/extension.ts create mode 100644 solid-table/src/components/editor/examples/table/index.ts create mode 100644 solid-table/src/components/editor/sample/sample-doc-table.ts create mode 100644 solid-table/src/components/editor/ui/table-handle/index.ts create mode 100644 solid-table/src/components/editor/ui/table-handle/table-handle.tsx create mode 100644 solid-table/src/index.tsx create mode 100644 solid-table/tsconfig.app.json create mode 100644 solid-table/tsconfig.json create mode 100644 solid-table/tsconfig.node.json create mode 100644 solid-table/vite.config.ts create mode 100644 solid-text-align/.gitignore create mode 100644 solid-text-align/README.md create mode 100644 solid-text-align/index.html create mode 100644 solid-text-align/package.json create mode 100644 solid-text-align/src/App.tsx create mode 100644 solid-text-align/src/app.css create mode 100644 solid-text-align/src/components/editor/examples/text-align/editor.tsx create mode 100644 solid-text-align/src/components/editor/examples/text-align/extension.ts create mode 100644 solid-text-align/src/components/editor/examples/text-align/index.ts create mode 100644 solid-text-align/src/components/editor/examples/text-align/toolbar.tsx create mode 100644 solid-text-align/src/components/editor/sample/sample-doc-text-align.ts create mode 100644 solid-text-align/src/components/editor/ui/button/button.tsx create mode 100644 solid-text-align/src/components/editor/ui/button/index.ts create mode 100644 solid-text-align/src/index.tsx create mode 100644 solid-text-align/tsconfig.app.json create mode 100644 solid-text-align/tsconfig.json create mode 100644 solid-text-align/tsconfig.node.json create mode 100644 solid-text-align/vite.config.ts create mode 100644 solid-text-color/.gitignore create mode 100644 solid-text-color/README.md create mode 100644 solid-text-color/index.html create mode 100644 solid-text-color/package.json create mode 100644 solid-text-color/src/App.tsx create mode 100644 solid-text-color/src/app.css create mode 100644 solid-text-color/src/components/editor/examples/text-color/editor.tsx create mode 100644 solid-text-color/src/components/editor/examples/text-color/extension.ts create mode 100644 solid-text-color/src/components/editor/examples/text-color/index.ts create mode 100644 solid-text-color/src/components/editor/examples/text-color/inline-menu.tsx create mode 100644 solid-text-color/src/components/editor/sample/sample-doc-text-color.ts create mode 100644 solid-text-color/src/components/editor/ui/button/button.tsx create mode 100644 solid-text-color/src/components/editor/ui/button/index.ts create mode 100644 solid-text-color/src/index.tsx create mode 100644 solid-text-color/tsconfig.app.json create mode 100644 solid-text-color/tsconfig.json create mode 100644 solid-text-color/tsconfig.node.json create mode 100644 solid-text-color/vite.config.ts create mode 100644 solid-toolbar/.gitignore create mode 100644 solid-toolbar/README.md create mode 100644 solid-toolbar/index.html create mode 100644 solid-toolbar/package.json create mode 100644 solid-toolbar/src/App.tsx create mode 100644 solid-toolbar/src/app.css create mode 100644 solid-toolbar/src/components/editor/examples/toolbar/editor.tsx create mode 100644 solid-toolbar/src/components/editor/examples/toolbar/extension.ts create mode 100644 solid-toolbar/src/components/editor/examples/toolbar/index.ts create mode 100644 solid-toolbar/src/components/editor/sample/sample-uploader.ts create mode 100644 solid-toolbar/src/components/editor/ui/button/button.tsx create mode 100644 solid-toolbar/src/components/editor/ui/button/index.ts create mode 100644 solid-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-toolbar/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-toolbar/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-toolbar/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-toolbar/src/index.tsx create mode 100644 solid-toolbar/tsconfig.app.json create mode 100644 solid-toolbar/tsconfig.json create mode 100644 solid-toolbar/tsconfig.node.json create mode 100644 solid-toolbar/vite.config.ts create mode 100644 solid-typography/.gitignore create mode 100644 solid-typography/README.md create mode 100644 solid-typography/index.html create mode 100644 solid-typography/package.json create mode 100644 solid-typography/src/App.tsx create mode 100644 solid-typography/src/app.css create mode 100644 solid-typography/src/components/editor/examples/typography/editor.tsx create mode 100644 solid-typography/src/components/editor/examples/typography/extension.ts create mode 100644 solid-typography/src/components/editor/examples/typography/index.ts create mode 100644 solid-typography/src/components/editor/sample/katex.ts create mode 100644 solid-typography/src/components/editor/sample/sample-doc-typography.ts create mode 100644 solid-typography/src/components/editor/ui/block-handle/block-handle.tsx create mode 100644 solid-typography/src/components/editor/ui/block-handle/index.ts create mode 100644 solid-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx create mode 100644 solid-typography/src/components/editor/ui/drop-indicator/index.ts create mode 100644 solid-typography/src/index.tsx create mode 100644 solid-typography/tsconfig.app.json create mode 100644 solid-typography/tsconfig.json create mode 100644 solid-typography/tsconfig.node.json create mode 100644 solid-typography/vite.config.ts create mode 100644 solid-underline/.gitignore create mode 100644 solid-underline/README.md create mode 100644 solid-underline/index.html create mode 100644 solid-underline/package.json create mode 100644 solid-underline/src/App.tsx create mode 100644 solid-underline/src/app.css create mode 100644 solid-underline/src/components/editor/examples/underline/editor.tsx create mode 100644 solid-underline/src/components/editor/examples/underline/extension.ts create mode 100644 solid-underline/src/components/editor/examples/underline/index.ts create mode 100644 solid-underline/src/components/editor/sample/sample-doc-underline.ts create mode 100644 solid-underline/src/components/editor/ui/button/button.tsx create mode 100644 solid-underline/src/components/editor/ui/button/index.ts create mode 100644 solid-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-underline/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-underline/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-underline/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-underline/src/index.tsx create mode 100644 solid-underline/tsconfig.app.json create mode 100644 solid-underline/tsconfig.json create mode 100644 solid-underline/tsconfig.node.json create mode 100644 solid-underline/vite.config.ts create mode 100644 solid-unmount/.gitignore create mode 100644 solid-unmount/README.md create mode 100644 solid-unmount/index.html create mode 100644 solid-unmount/package.json create mode 100644 solid-unmount/src/App.tsx create mode 100644 solid-unmount/src/app.css create mode 100644 solid-unmount/src/components/editor/examples/unmount/editor-component.tsx create mode 100644 solid-unmount/src/components/editor/examples/unmount/editor.tsx create mode 100644 solid-unmount/src/components/editor/examples/unmount/extension-component.tsx create mode 100644 solid-unmount/src/components/editor/examples/unmount/index.ts create mode 100644 solid-unmount/src/components/editor/ui/button/button.tsx create mode 100644 solid-unmount/src/components/editor/ui/button/index.ts create mode 100644 solid-unmount/src/components/editor/ui/inline-menu/index.ts create mode 100644 solid-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx create mode 100644 solid-unmount/src/index.tsx create mode 100644 solid-unmount/tsconfig.app.json create mode 100644 solid-unmount/tsconfig.json create mode 100644 solid-unmount/tsconfig.node.json create mode 100644 solid-unmount/vite.config.ts create mode 100644 solid-user-menu-dynamic/.gitignore create mode 100644 solid-user-menu-dynamic/README.md create mode 100644 solid-user-menu-dynamic/index.html create mode 100644 solid-user-menu-dynamic/package.json create mode 100644 solid-user-menu-dynamic/src/App.tsx create mode 100644 solid-user-menu-dynamic/src/app.css create mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx create mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts create mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts create mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts create mode 100644 solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx create mode 100644 solid-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts create mode 100644 solid-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts create mode 100644 solid-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts create mode 100644 solid-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 solid-user-menu-dynamic/src/index.tsx create mode 100644 solid-user-menu-dynamic/tsconfig.app.json create mode 100644 solid-user-menu-dynamic/tsconfig.json create mode 100644 solid-user-menu-dynamic/tsconfig.node.json create mode 100644 solid-user-menu-dynamic/vite.config.ts create mode 100644 solid-user-menu/.gitignore create mode 100644 solid-user-menu/README.md create mode 100644 solid-user-menu/index.html create mode 100644 solid-user-menu/package.json create mode 100644 solid-user-menu/src/App.tsx create mode 100644 solid-user-menu/src/app.css create mode 100644 solid-user-menu/src/components/editor/examples/user-menu/editor.tsx create mode 100644 solid-user-menu/src/components/editor/examples/user-menu/extension.ts create mode 100644 solid-user-menu/src/components/editor/examples/user-menu/index.ts create mode 100644 solid-user-menu/src/components/editor/sample/sample-tag-data.ts create mode 100644 solid-user-menu/src/components/editor/sample/sample-user-data.ts create mode 100644 solid-user-menu/src/components/editor/ui/tag-menu/index.ts create mode 100644 solid-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx create mode 100644 solid-user-menu/src/components/editor/ui/user-menu/index.ts create mode 100644 solid-user-menu/src/components/editor/ui/user-menu/user-menu.tsx create mode 100644 solid-user-menu/src/index.tsx create mode 100644 solid-user-menu/tsconfig.app.json create mode 100644 solid-user-menu/tsconfig.json create mode 100644 solid-user-menu/tsconfig.node.json create mode 100644 solid-user-menu/vite.config.ts create mode 100644 solid-word-counter/.gitignore create mode 100644 solid-word-counter/README.md create mode 100644 solid-word-counter/index.html create mode 100644 solid-word-counter/package.json create mode 100644 solid-word-counter/src/App.tsx create mode 100644 solid-word-counter/src/app.css create mode 100644 solid-word-counter/src/components/editor/examples/word-counter/editor.tsx create mode 100644 solid-word-counter/src/components/editor/examples/word-counter/extension.ts create mode 100644 solid-word-counter/src/components/editor/examples/word-counter/index.ts create mode 100644 solid-word-counter/src/components/editor/sample/sample-doc-word-counter.ts create mode 100644 solid-word-counter/src/components/editor/ui/word-counter/index.ts create mode 100644 solid-word-counter/src/components/editor/ui/word-counter/word-counter.tsx create mode 100644 solid-word-counter/src/index.tsx create mode 100644 solid-word-counter/tsconfig.app.json create mode 100644 solid-word-counter/tsconfig.json create mode 100644 solid-word-counter/tsconfig.node.json create mode 100644 solid-word-counter/vite.config.ts create mode 100644 solid-yjs/.gitignore create mode 100644 solid-yjs/README.md create mode 100644 solid-yjs/index.html create mode 100644 solid-yjs/package.json create mode 100644 solid-yjs/src/App.tsx create mode 100644 solid-yjs/src/app.css create mode 100644 solid-yjs/src/components/editor/examples/yjs/editor-component.tsx create mode 100644 solid-yjs/src/components/editor/examples/yjs/editor.tsx create mode 100644 solid-yjs/src/components/editor/examples/yjs/extension.ts create mode 100644 solid-yjs/src/components/editor/examples/yjs/index.ts create mode 100644 solid-yjs/src/components/editor/ui/button/button.tsx create mode 100644 solid-yjs/src/components/editor/ui/button/index.ts create mode 100644 solid-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx create mode 100644 solid-yjs/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 solid-yjs/src/components/editor/ui/toolbar/index.ts create mode 100644 solid-yjs/src/components/editor/ui/toolbar/toolbar.tsx create mode 100644 solid-yjs/src/index.tsx create mode 100644 solid-yjs/tsconfig.app.json create mode 100644 solid-yjs/tsconfig.json create mode 100644 solid-yjs/tsconfig.node.json create mode 100644 solid-yjs/vite.config.ts create mode 100644 svelte-block-handle/.gitignore create mode 100644 svelte-block-handle/README.md create mode 100644 svelte-block-handle/index.html create mode 100644 svelte-block-handle/package.json create mode 100644 svelte-block-handle/src/App.svelte create mode 100644 svelte-block-handle/src/app.css create mode 100644 svelte-block-handle/src/components/editor/examples/block-handle/editor.svelte create mode 100644 svelte-block-handle/src/components/editor/examples/block-handle/extension.ts create mode 100644 svelte-block-handle/src/components/editor/examples/block-handle/index.ts create mode 100644 svelte-block-handle/src/components/editor/sample/sample-doc-block-handle.ts create mode 100644 svelte-block-handle/src/components/editor/ui/block-handle/block-handle.svelte create mode 100644 svelte-block-handle/src/components/editor/ui/block-handle/index.ts create mode 100644 svelte-block-handle/src/components/editor/ui/code-block-view/code-block-view.svelte create mode 100644 svelte-block-handle/src/components/editor/ui/code-block-view/index.ts create mode 100644 svelte-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.svelte create mode 100644 svelte-block-handle/src/components/editor/ui/drop-indicator/index.ts create mode 100644 svelte-block-handle/src/main.ts create mode 100644 svelte-block-handle/src/vite-env.d.ts create mode 100644 svelte-block-handle/svelte.config.js create mode 100644 svelte-block-handle/tsconfig.json create mode 100644 svelte-block-handle/tsconfig.node.json create mode 100644 svelte-block-handle/vite.config.ts create mode 100644 svelte-blockquote/.gitignore create mode 100644 svelte-blockquote/README.md create mode 100644 svelte-blockquote/index.html create mode 100644 svelte-blockquote/package.json create mode 100644 svelte-blockquote/src/App.svelte create mode 100644 svelte-blockquote/src/app.css create mode 100644 svelte-blockquote/src/components/editor/examples/blockquote/editor.svelte create mode 100644 svelte-blockquote/src/components/editor/examples/blockquote/extension.ts create mode 100644 svelte-blockquote/src/components/editor/examples/blockquote/index.ts create mode 100644 svelte-blockquote/src/components/editor/ui/button/button.svelte create mode 100644 svelte-blockquote/src/components/editor/ui/button/index.ts create mode 100644 svelte-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-blockquote/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-blockquote/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-blockquote/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-blockquote/src/main.ts create mode 100644 svelte-blockquote/src/vite-env.d.ts create mode 100644 svelte-blockquote/svelte.config.js create mode 100644 svelte-blockquote/tsconfig.json create mode 100644 svelte-blockquote/tsconfig.node.json create mode 100644 svelte-blockquote/vite.config.ts create mode 100644 svelte-bold/.gitignore create mode 100644 svelte-bold/README.md create mode 100644 svelte-bold/index.html create mode 100644 svelte-bold/package.json create mode 100644 svelte-bold/src/App.svelte create mode 100644 svelte-bold/src/app.css create mode 100644 svelte-bold/src/components/editor/examples/bold/editor.svelte create mode 100644 svelte-bold/src/components/editor/examples/bold/extension.ts create mode 100644 svelte-bold/src/components/editor/examples/bold/index.ts create mode 100644 svelte-bold/src/components/editor/sample/sample-doc-bold.ts create mode 100644 svelte-bold/src/components/editor/ui/button/button.svelte create mode 100644 svelte-bold/src/components/editor/ui/button/index.ts create mode 100644 svelte-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-bold/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-bold/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-bold/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-bold/src/main.ts create mode 100644 svelte-bold/src/vite-env.d.ts create mode 100644 svelte-bold/svelte.config.js create mode 100644 svelte-bold/tsconfig.json create mode 100644 svelte-bold/tsconfig.node.json create mode 100644 svelte-bold/vite.config.ts create mode 100644 svelte-change-tracking/.gitignore create mode 100644 svelte-change-tracking/README.md create mode 100644 svelte-change-tracking/index.html create mode 100644 svelte-change-tracking/package.json create mode 100644 svelte-change-tracking/src/App.svelte create mode 100644 svelte-change-tracking/src/app.css create mode 100644 svelte-change-tracking/src/components/editor/examples/change-tracking/editor-diff.svelte create mode 100644 svelte-change-tracking/src/components/editor/examples/change-tracking/editor-main.svelte create mode 100644 svelte-change-tracking/src/components/editor/examples/change-tracking/editor.svelte create mode 100644 svelte-change-tracking/src/components/editor/examples/change-tracking/index.ts create mode 100644 svelte-change-tracking/src/main.ts create mode 100644 svelte-change-tracking/src/vite-env.d.ts create mode 100644 svelte-change-tracking/svelte.config.js create mode 100644 svelte-change-tracking/tsconfig.json create mode 100644 svelte-change-tracking/tsconfig.node.json create mode 100644 svelte-change-tracking/vite.config.ts create mode 100644 svelte-code-block-themes/.gitignore create mode 100644 svelte-code-block-themes/README.md create mode 100644 svelte-code-block-themes/index.html create mode 100644 svelte-code-block-themes/package.json create mode 100644 svelte-code-block-themes/src/App.svelte create mode 100644 svelte-code-block-themes/src/app.css create mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/editor.svelte create mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts create mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/index.ts create mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.svelte create mode 100644 svelte-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.svelte create mode 100644 svelte-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 svelte-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.svelte create mode 100644 svelte-code-block-themes/src/components/editor/ui/code-block-view/index.ts create mode 100644 svelte-code-block-themes/src/main.ts create mode 100644 svelte-code-block-themes/src/vite-env.d.ts create mode 100644 svelte-code-block-themes/svelte.config.js create mode 100644 svelte-code-block-themes/tsconfig.json create mode 100644 svelte-code-block-themes/tsconfig.node.json create mode 100644 svelte-code-block-themes/vite.config.ts create mode 100644 svelte-code-block/.gitignore create mode 100644 svelte-code-block/README.md create mode 100644 svelte-code-block/index.html create mode 100644 svelte-code-block/package.json create mode 100644 svelte-code-block/src/App.svelte create mode 100644 svelte-code-block/src/app.css create mode 100644 svelte-code-block/src/components/editor/examples/code-block/editor.svelte create mode 100644 svelte-code-block/src/components/editor/examples/code-block/extension.ts create mode 100644 svelte-code-block/src/components/editor/examples/code-block/index.ts create mode 100644 svelte-code-block/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 svelte-code-block/src/components/editor/ui/button/button.svelte create mode 100644 svelte-code-block/src/components/editor/ui/button/index.ts create mode 100644 svelte-code-block/src/components/editor/ui/code-block-view/code-block-view.svelte create mode 100644 svelte-code-block/src/components/editor/ui/code-block-view/index.ts create mode 100644 svelte-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-code-block/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-code-block/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-code-block/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-code-block/src/main.ts create mode 100644 svelte-code-block/src/vite-env.d.ts create mode 100644 svelte-code-block/svelte.config.js create mode 100644 svelte-code-block/tsconfig.json create mode 100644 svelte-code-block/tsconfig.node.json create mode 100644 svelte-code-block/vite.config.ts create mode 100644 svelte-code/.gitignore create mode 100644 svelte-code/README.md create mode 100644 svelte-code/index.html create mode 100644 svelte-code/package.json create mode 100644 svelte-code/src/App.svelte create mode 100644 svelte-code/src/app.css create mode 100644 svelte-code/src/components/editor/examples/code/editor.svelte create mode 100644 svelte-code/src/components/editor/examples/code/extension.ts create mode 100644 svelte-code/src/components/editor/examples/code/index.ts create mode 100644 svelte-code/src/components/editor/sample/sample-doc-code.ts create mode 100644 svelte-code/src/components/editor/ui/button/button.svelte create mode 100644 svelte-code/src/components/editor/ui/button/index.ts create mode 100644 svelte-code/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-code/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-code/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-code/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-code/src/main.ts create mode 100644 svelte-code/src/vite-env.d.ts create mode 100644 svelte-code/svelte.config.js create mode 100644 svelte-code/tsconfig.json create mode 100644 svelte-code/tsconfig.node.json create mode 100644 svelte-code/vite.config.ts create mode 100644 svelte-drop-cursor/.gitignore create mode 100644 svelte-drop-cursor/README.md create mode 100644 svelte-drop-cursor/index.html create mode 100644 svelte-drop-cursor/package.json create mode 100644 svelte-drop-cursor/src/App.svelte create mode 100644 svelte-drop-cursor/src/app.css create mode 100644 svelte-drop-cursor/src/components/editor/examples/drop-cursor/editor.svelte create mode 100644 svelte-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts create mode 100644 svelte-drop-cursor/src/components/editor/examples/drop-cursor/index.ts create mode 100644 svelte-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts create mode 100644 svelte-drop-cursor/src/main.ts create mode 100644 svelte-drop-cursor/src/vite-env.d.ts create mode 100644 svelte-drop-cursor/svelte.config.js create mode 100644 svelte-drop-cursor/tsconfig.json create mode 100644 svelte-drop-cursor/tsconfig.node.json create mode 100644 svelte-drop-cursor/vite.config.ts create mode 100644 svelte-emoji-rules/.gitignore create mode 100644 svelte-emoji-rules/README.md create mode 100644 svelte-emoji-rules/index.html create mode 100644 svelte-emoji-rules/package.json create mode 100644 svelte-emoji-rules/src/App.svelte create mode 100644 svelte-emoji-rules/src/app.css create mode 100644 svelte-emoji-rules/src/components/editor/examples/emoji-rules/editor.svelte create mode 100644 svelte-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts create mode 100644 svelte-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts create mode 100644 svelte-emoji-rules/src/components/editor/examples/emoji-rules/index.ts create mode 100644 svelte-emoji-rules/src/main.ts create mode 100644 svelte-emoji-rules/src/vite-env.d.ts create mode 100644 svelte-emoji-rules/svelte.config.js create mode 100644 svelte-emoji-rules/tsconfig.json create mode 100644 svelte-emoji-rules/tsconfig.node.json create mode 100644 svelte-emoji-rules/vite.config.ts create mode 100644 svelte-full/.gitignore create mode 100644 svelte-full/README.md create mode 100644 svelte-full/index.html create mode 100644 svelte-full/package.json create mode 100644 svelte-full/src/App.svelte create mode 100644 svelte-full/src/app.css create mode 100644 svelte-full/src/components/editor/examples/full/editor.svelte create mode 100644 svelte-full/src/components/editor/examples/full/extension.ts create mode 100644 svelte-full/src/components/editor/examples/full/index.ts create mode 100644 svelte-full/src/components/editor/sample/katex.ts create mode 100644 svelte-full/src/components/editor/sample/sample-doc-full.ts create mode 100644 svelte-full/src/components/editor/sample/sample-tag-data.ts create mode 100644 svelte-full/src/components/editor/sample/sample-uploader.ts create mode 100644 svelte-full/src/components/editor/sample/sample-user-data.ts create mode 100644 svelte-full/src/components/editor/ui/block-handle/block-handle.svelte create mode 100644 svelte-full/src/components/editor/ui/block-handle/index.ts create mode 100644 svelte-full/src/components/editor/ui/button/button.svelte create mode 100644 svelte-full/src/components/editor/ui/button/index.ts create mode 100644 svelte-full/src/components/editor/ui/code-block-view/code-block-view.svelte create mode 100644 svelte-full/src/components/editor/ui/code-block-view/index.ts create mode 100644 svelte-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte create mode 100644 svelte-full/src/components/editor/ui/drop-indicator/index.ts create mode 100644 svelte-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-full/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-full/src/components/editor/ui/image-view/image-view.svelte create mode 100644 svelte-full/src/components/editor/ui/image-view/index.ts create mode 100644 svelte-full/src/components/editor/ui/inline-menu/index.ts create mode 100644 svelte-full/src/components/editor/ui/inline-menu/inline-menu.svelte create mode 100644 svelte-full/src/components/editor/ui/slash-menu/index.ts create mode 100644 svelte-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte create mode 100644 svelte-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte create mode 100644 svelte-full/src/components/editor/ui/slash-menu/slash-menu.svelte create mode 100644 svelte-full/src/components/editor/ui/table-handle/index.ts create mode 100644 svelte-full/src/components/editor/ui/table-handle/table-handle.svelte create mode 100644 svelte-full/src/components/editor/ui/tag-menu/index.ts create mode 100644 svelte-full/src/components/editor/ui/tag-menu/tag-menu.svelte create mode 100644 svelte-full/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-full/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-full/src/components/editor/ui/user-menu/index.ts create mode 100644 svelte-full/src/components/editor/ui/user-menu/user-menu.svelte create mode 100644 svelte-full/src/main.ts create mode 100644 svelte-full/src/vite-env.d.ts create mode 100644 svelte-full/svelte.config.js create mode 100644 svelte-full/tsconfig.json create mode 100644 svelte-full/tsconfig.node.json create mode 100644 svelte-full/vite.config.ts create mode 100644 svelte-gap-cursor/.gitignore create mode 100644 svelte-gap-cursor/README.md create mode 100644 svelte-gap-cursor/index.html create mode 100644 svelte-gap-cursor/package.json create mode 100644 svelte-gap-cursor/src/App.svelte create mode 100644 svelte-gap-cursor/src/app.css create mode 100644 svelte-gap-cursor/src/components/editor/examples/gap-cursor/editor.svelte create mode 100644 svelte-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts create mode 100644 svelte-gap-cursor/src/components/editor/examples/gap-cursor/index.ts create mode 100644 svelte-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts create mode 100644 svelte-gap-cursor/src/main.ts create mode 100644 svelte-gap-cursor/src/vite-env.d.ts create mode 100644 svelte-gap-cursor/svelte.config.js create mode 100644 svelte-gap-cursor/tsconfig.json create mode 100644 svelte-gap-cursor/tsconfig.node.json create mode 100644 svelte-gap-cursor/vite.config.ts create mode 100644 svelte-hard-break/.gitignore create mode 100644 svelte-hard-break/README.md create mode 100644 svelte-hard-break/index.html create mode 100644 svelte-hard-break/package.json create mode 100644 svelte-hard-break/src/App.svelte create mode 100644 svelte-hard-break/src/app.css create mode 100644 svelte-hard-break/src/components/editor/examples/hard-break/editor.svelte create mode 100644 svelte-hard-break/src/components/editor/examples/hard-break/extension.ts create mode 100644 svelte-hard-break/src/components/editor/examples/hard-break/index.ts create mode 100644 svelte-hard-break/src/components/editor/examples/hard-break/toolbar.svelte create mode 100644 svelte-hard-break/src/components/editor/sample/sample-doc-hard-break.ts create mode 100644 svelte-hard-break/src/components/editor/ui/button/button.svelte create mode 100644 svelte-hard-break/src/components/editor/ui/button/index.ts create mode 100644 svelte-hard-break/src/main.ts create mode 100644 svelte-hard-break/src/vite-env.d.ts create mode 100644 svelte-hard-break/svelte.config.js create mode 100644 svelte-hard-break/tsconfig.json create mode 100644 svelte-hard-break/tsconfig.node.json create mode 100644 svelte-hard-break/vite.config.ts create mode 100644 svelte-heading/.gitignore create mode 100644 svelte-heading/README.md create mode 100644 svelte-heading/index.html create mode 100644 svelte-heading/package.json create mode 100644 svelte-heading/src/App.svelte create mode 100644 svelte-heading/src/app.css create mode 100644 svelte-heading/src/components/editor/examples/heading/editor.svelte create mode 100644 svelte-heading/src/components/editor/examples/heading/extension.ts create mode 100644 svelte-heading/src/components/editor/examples/heading/index.ts create mode 100644 svelte-heading/src/components/editor/sample/sample-doc-heading.ts create mode 100644 svelte-heading/src/components/editor/ui/button/button.svelte create mode 100644 svelte-heading/src/components/editor/ui/button/index.ts create mode 100644 svelte-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-heading/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-heading/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-heading/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-heading/src/main.ts create mode 100644 svelte-heading/src/vite-env.d.ts create mode 100644 svelte-heading/svelte.config.js create mode 100644 svelte-heading/tsconfig.json create mode 100644 svelte-heading/tsconfig.node.json create mode 100644 svelte-heading/vite.config.ts create mode 100644 svelte-highlight/.gitignore create mode 100644 svelte-highlight/README.md create mode 100644 svelte-highlight/index.html create mode 100644 svelte-highlight/package.json create mode 100644 svelte-highlight/src/App.svelte create mode 100644 svelte-highlight/src/app.css create mode 100644 svelte-highlight/src/components/editor/examples/highlight/editor.svelte create mode 100644 svelte-highlight/src/components/editor/examples/highlight/extension.ts create mode 100644 svelte-highlight/src/components/editor/examples/highlight/index.ts create mode 100644 svelte-highlight/src/components/editor/examples/highlight/toolbar.svelte create mode 100644 svelte-highlight/src/components/editor/sample/sample-doc-highlight.ts create mode 100644 svelte-highlight/src/components/editor/ui/button/button.svelte create mode 100644 svelte-highlight/src/components/editor/ui/button/index.ts create mode 100644 svelte-highlight/src/main.ts create mode 100644 svelte-highlight/src/vite-env.d.ts create mode 100644 svelte-highlight/svelte.config.js create mode 100644 svelte-highlight/tsconfig.json create mode 100644 svelte-highlight/tsconfig.node.json create mode 100644 svelte-highlight/vite.config.ts create mode 100644 svelte-horizontal-rule/.gitignore create mode 100644 svelte-horizontal-rule/README.md create mode 100644 svelte-horizontal-rule/index.html create mode 100644 svelte-horizontal-rule/package.json create mode 100644 svelte-horizontal-rule/src/App.svelte create mode 100644 svelte-horizontal-rule/src/app.css create mode 100644 svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.svelte create mode 100644 svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts create mode 100644 svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts create mode 100644 svelte-horizontal-rule/src/components/editor/ui/button/button.svelte create mode 100644 svelte-horizontal-rule/src/components/editor/ui/button/index.ts create mode 100644 svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-horizontal-rule/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-horizontal-rule/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-horizontal-rule/src/main.ts create mode 100644 svelte-horizontal-rule/src/vite-env.d.ts create mode 100644 svelte-horizontal-rule/svelte.config.js create mode 100644 svelte-horizontal-rule/tsconfig.json create mode 100644 svelte-horizontal-rule/tsconfig.node.json create mode 100644 svelte-horizontal-rule/vite.config.ts create mode 100644 svelte-image-view/.gitignore create mode 100644 svelte-image-view/README.md create mode 100644 svelte-image-view/index.html create mode 100644 svelte-image-view/package.json create mode 100644 svelte-image-view/src/App.svelte create mode 100644 svelte-image-view/src/app.css create mode 100644 svelte-image-view/src/components/editor/examples/image-view/editor.svelte create mode 100644 svelte-image-view/src/components/editor/examples/image-view/extension.ts create mode 100644 svelte-image-view/src/components/editor/examples/image-view/index.ts create mode 100644 svelte-image-view/src/components/editor/sample/sample-doc-image.ts create mode 100644 svelte-image-view/src/components/editor/sample/sample-uploader.ts create mode 100644 svelte-image-view/src/components/editor/ui/image-view/image-view.svelte create mode 100644 svelte-image-view/src/components/editor/ui/image-view/index.ts create mode 100644 svelte-image-view/src/main.ts create mode 100644 svelte-image-view/src/vite-env.d.ts create mode 100644 svelte-image-view/svelte.config.js create mode 100644 svelte-image-view/tsconfig.json create mode 100644 svelte-image-view/tsconfig.node.json create mode 100644 svelte-image-view/vite.config.ts create mode 100644 svelte-inline-menu/.gitignore create mode 100644 svelte-inline-menu/README.md create mode 100644 svelte-inline-menu/index.html create mode 100644 svelte-inline-menu/package.json create mode 100644 svelte-inline-menu/src/App.svelte create mode 100644 svelte-inline-menu/src/app.css create mode 100644 svelte-inline-menu/src/components/editor/examples/inline-menu/editor.svelte create mode 100644 svelte-inline-menu/src/components/editor/examples/inline-menu/extension.ts create mode 100644 svelte-inline-menu/src/components/editor/examples/inline-menu/index.ts create mode 100644 svelte-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts create mode 100644 svelte-inline-menu/src/components/editor/ui/button/button.svelte create mode 100644 svelte-inline-menu/src/components/editor/ui/button/index.ts create mode 100644 svelte-inline-menu/src/components/editor/ui/inline-menu/index.ts create mode 100644 svelte-inline-menu/src/components/editor/ui/inline-menu/inline-menu.svelte create mode 100644 svelte-inline-menu/src/main.ts create mode 100644 svelte-inline-menu/src/vite-env.d.ts create mode 100644 svelte-inline-menu/svelte.config.js create mode 100644 svelte-inline-menu/tsconfig.json create mode 100644 svelte-inline-menu/tsconfig.node.json create mode 100644 svelte-inline-menu/vite.config.ts create mode 100644 svelte-italic/.gitignore create mode 100644 svelte-italic/README.md create mode 100644 svelte-italic/index.html create mode 100644 svelte-italic/package.json create mode 100644 svelte-italic/src/App.svelte create mode 100644 svelte-italic/src/app.css create mode 100644 svelte-italic/src/components/editor/examples/italic/editor.svelte create mode 100644 svelte-italic/src/components/editor/examples/italic/extension.ts create mode 100644 svelte-italic/src/components/editor/examples/italic/index.ts create mode 100644 svelte-italic/src/components/editor/sample/sample-doc-italic.ts create mode 100644 svelte-italic/src/components/editor/ui/button/button.svelte create mode 100644 svelte-italic/src/components/editor/ui/button/index.ts create mode 100644 svelte-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-italic/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-italic/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-italic/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-italic/src/main.ts create mode 100644 svelte-italic/src/vite-env.d.ts create mode 100644 svelte-italic/svelte.config.js create mode 100644 svelte-italic/tsconfig.json create mode 100644 svelte-italic/tsconfig.node.json create mode 100644 svelte-italic/vite.config.ts create mode 100644 svelte-katex/.gitignore create mode 100644 svelte-katex/README.md create mode 100644 svelte-katex/index.html create mode 100644 svelte-katex/package.json create mode 100644 svelte-katex/src/App.svelte create mode 100644 svelte-katex/src/app.css create mode 100644 svelte-katex/src/components/editor/examples/katex/editor.svelte create mode 100644 svelte-katex/src/components/editor/examples/katex/extension.ts create mode 100644 svelte-katex/src/components/editor/examples/katex/index.ts create mode 100644 svelte-katex/src/components/editor/sample/katex.ts create mode 100644 svelte-katex/src/components/editor/sample/sample-doc-tex.ts create mode 100644 svelte-katex/src/main.ts create mode 100644 svelte-katex/src/vite-env.d.ts create mode 100644 svelte-katex/svelte.config.js create mode 100644 svelte-katex/tsconfig.json create mode 100644 svelte-katex/tsconfig.node.json create mode 100644 svelte-katex/vite.config.ts create mode 100644 svelte-keymap/.gitignore create mode 100644 svelte-keymap/README.md create mode 100644 svelte-keymap/index.html create mode 100644 svelte-keymap/package.json create mode 100644 svelte-keymap/src/App.svelte create mode 100644 svelte-keymap/src/app.css create mode 100644 svelte-keymap/src/components/editor/examples/keymap/editor.svelte create mode 100644 svelte-keymap/src/components/editor/examples/keymap/extension.ts create mode 100644 svelte-keymap/src/components/editor/examples/keymap/index.ts create mode 100644 svelte-keymap/src/components/editor/examples/keymap/toolbar.svelte create mode 100644 svelte-keymap/src/components/editor/ui/button/button.svelte create mode 100644 svelte-keymap/src/components/editor/ui/button/index.ts create mode 100644 svelte-keymap/src/main.ts create mode 100644 svelte-keymap/src/vite-env.d.ts create mode 100644 svelte-keymap/svelte.config.js create mode 100644 svelte-keymap/tsconfig.json create mode 100644 svelte-keymap/tsconfig.node.json create mode 100644 svelte-keymap/vite.config.ts create mode 100644 svelte-link-mark-view/.gitignore create mode 100644 svelte-link-mark-view/README.md create mode 100644 svelte-link-mark-view/index.html create mode 100644 svelte-link-mark-view/package.json create mode 100644 svelte-link-mark-view/src/App.svelte create mode 100644 svelte-link-mark-view/src/app.css create mode 100644 svelte-link-mark-view/src/components/editor/examples/link-mark-view/editor.svelte create mode 100644 svelte-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts create mode 100644 svelte-link-mark-view/src/components/editor/examples/link-mark-view/index.ts create mode 100644 svelte-link-mark-view/src/components/editor/examples/link-mark-view/link-view.svelte create mode 100644 svelte-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts create mode 100644 svelte-link-mark-view/src/main.ts create mode 100644 svelte-link-mark-view/src/vite-env.d.ts create mode 100644 svelte-link-mark-view/svelte.config.js create mode 100644 svelte-link-mark-view/tsconfig.json create mode 100644 svelte-link-mark-view/tsconfig.node.json create mode 100644 svelte-link-mark-view/vite.config.ts create mode 100644 svelte-link/.gitignore create mode 100644 svelte-link/README.md create mode 100644 svelte-link/index.html create mode 100644 svelte-link/package.json create mode 100644 svelte-link/src/App.svelte create mode 100644 svelte-link/src/app.css create mode 100644 svelte-link/src/components/editor/examples/link/editor.svelte create mode 100644 svelte-link/src/components/editor/examples/link/extension.ts create mode 100644 svelte-link/src/components/editor/examples/link/index.ts create mode 100644 svelte-link/src/components/editor/sample/sample-doc-link.ts create mode 100644 svelte-link/src/components/editor/ui/button/button.svelte create mode 100644 svelte-link/src/components/editor/ui/button/index.ts create mode 100644 svelte-link/src/components/editor/ui/inline-menu/index.ts create mode 100644 svelte-link/src/components/editor/ui/inline-menu/inline-menu.svelte create mode 100644 svelte-link/src/main.ts create mode 100644 svelte-link/src/vite-env.d.ts create mode 100644 svelte-link/svelte.config.js create mode 100644 svelte-link/tsconfig.json create mode 100644 svelte-link/tsconfig.node.json create mode 100644 svelte-link/vite.config.ts create mode 100644 svelte-list-custom-checkbox/.gitignore create mode 100644 svelte-list-custom-checkbox/README.md create mode 100644 svelte-list-custom-checkbox/index.html create mode 100644 svelte-list-custom-checkbox/package.json create mode 100644 svelte-list-custom-checkbox/src/App.svelte create mode 100644 svelte-list-custom-checkbox/src/app.css create mode 100644 svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css create mode 100644 svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.svelte create mode 100644 svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts create mode 100644 svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts create mode 100644 svelte-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts create mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/button/button.svelte create mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/button/index.ts create mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-list-custom-checkbox/src/main.ts create mode 100644 svelte-list-custom-checkbox/src/vite-env.d.ts create mode 100644 svelte-list-custom-checkbox/svelte.config.js create mode 100644 svelte-list-custom-checkbox/tsconfig.json create mode 100644 svelte-list-custom-checkbox/tsconfig.node.json create mode 100644 svelte-list-custom-checkbox/vite.config.ts create mode 100644 svelte-list/.gitignore create mode 100644 svelte-list/README.md create mode 100644 svelte-list/index.html create mode 100644 svelte-list/package.json create mode 100644 svelte-list/src/App.svelte create mode 100644 svelte-list/src/app.css create mode 100644 svelte-list/src/components/editor/examples/list/editor.svelte create mode 100644 svelte-list/src/components/editor/examples/list/extension.ts create mode 100644 svelte-list/src/components/editor/examples/list/index.ts create mode 100644 svelte-list/src/components/editor/sample/sample-doc-list.ts create mode 100644 svelte-list/src/components/editor/ui/button/button.svelte create mode 100644 svelte-list/src/components/editor/ui/button/index.ts create mode 100644 svelte-list/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-list/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-list/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-list/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-list/src/main.ts create mode 100644 svelte-list/src/vite-env.d.ts create mode 100644 svelte-list/svelte.config.js create mode 100644 svelte-list/tsconfig.json create mode 100644 svelte-list/tsconfig.node.json create mode 100644 svelte-list/vite.config.ts create mode 100644 svelte-loro/.gitignore create mode 100644 svelte-loro/README.md create mode 100644 svelte-loro/index.html create mode 100644 svelte-loro/package.json create mode 100644 svelte-loro/src/App.svelte create mode 100644 svelte-loro/src/app.css create mode 100644 svelte-loro/src/components/editor/examples/loro/editor-component.svelte create mode 100644 svelte-loro/src/components/editor/examples/loro/editor.svelte create mode 100644 svelte-loro/src/components/editor/examples/loro/extension.ts create mode 100644 svelte-loro/src/components/editor/examples/loro/index.ts create mode 100644 svelte-loro/src/components/editor/ui/button/button.svelte create mode 100644 svelte-loro/src/components/editor/ui/button/index.ts create mode 100644 svelte-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-loro/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-loro/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-loro/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-loro/src/main.ts create mode 100644 svelte-loro/src/vite-env.d.ts create mode 100644 svelte-loro/svelte.config.js create mode 100644 svelte-loro/tsconfig.json create mode 100644 svelte-loro/tsconfig.node.json create mode 100644 svelte-loro/vite.config.ts create mode 100644 svelte-mark-rule/.gitignore create mode 100644 svelte-mark-rule/README.md create mode 100644 svelte-mark-rule/index.html create mode 100644 svelte-mark-rule/package.json create mode 100644 svelte-mark-rule/src/App.svelte create mode 100644 svelte-mark-rule/src/app.css create mode 100644 svelte-mark-rule/src/components/editor/examples/mark-rule/editor.svelte create mode 100644 svelte-mark-rule/src/components/editor/examples/mark-rule/extension.ts create mode 100644 svelte-mark-rule/src/components/editor/examples/mark-rule/index.ts create mode 100644 svelte-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts create mode 100644 svelte-mark-rule/src/main.ts create mode 100644 svelte-mark-rule/src/vite-env.d.ts create mode 100644 svelte-mark-rule/svelte.config.js create mode 100644 svelte-mark-rule/tsconfig.json create mode 100644 svelte-mark-rule/tsconfig.node.json create mode 100644 svelte-mark-rule/vite.config.ts create mode 100644 svelte-minimal/.gitignore create mode 100644 svelte-minimal/README.md create mode 100644 svelte-minimal/index.html create mode 100644 svelte-minimal/package.json create mode 100644 svelte-minimal/src/App.svelte create mode 100644 svelte-minimal/src/app.css create mode 100644 svelte-minimal/src/components/editor/examples/minimal/editor.svelte create mode 100644 svelte-minimal/src/components/editor/examples/minimal/index.ts create mode 100644 svelte-minimal/src/main.ts create mode 100644 svelte-minimal/src/vite-env.d.ts create mode 100644 svelte-minimal/svelte.config.js create mode 100644 svelte-minimal/tsconfig.json create mode 100644 svelte-minimal/tsconfig.node.json create mode 100644 svelte-minimal/vite.config.ts create mode 100644 svelte-page/.gitignore create mode 100644 svelte-page/README.md create mode 100644 svelte-page/index.html create mode 100644 svelte-page/package.json create mode 100644 svelte-page/src/App.svelte create mode 100644 svelte-page/src/app.css create mode 100644 svelte-page/src/components/editor/examples/page/editor.svelte create mode 100644 svelte-page/src/components/editor/examples/page/extension.ts create mode 100644 svelte-page/src/components/editor/examples/page/index.ts create mode 100644 svelte-page/src/components/editor/examples/page/paper-controller.svelte create mode 100644 svelte-page/src/components/editor/examples/page/zoom.css create mode 100644 svelte-page/src/components/editor/sample/sample-doc-page.ts create mode 100644 svelte-page/src/main.ts create mode 100644 svelte-page/src/vite-env.d.ts create mode 100644 svelte-page/svelte.config.js create mode 100644 svelte-page/tsconfig.json create mode 100644 svelte-page/tsconfig.node.json create mode 100644 svelte-page/vite.config.ts create mode 100644 svelte-placeholder/.gitignore create mode 100644 svelte-placeholder/README.md create mode 100644 svelte-placeholder/index.html create mode 100644 svelte-placeholder/package.json create mode 100644 svelte-placeholder/src/App.svelte create mode 100644 svelte-placeholder/src/app.css create mode 100644 svelte-placeholder/src/components/editor/examples/placeholder/editor.svelte create mode 100644 svelte-placeholder/src/components/editor/examples/placeholder/extension.ts create mode 100644 svelte-placeholder/src/components/editor/examples/placeholder/index.ts create mode 100644 svelte-placeholder/src/main.ts create mode 100644 svelte-placeholder/src/vite-env.d.ts create mode 100644 svelte-placeholder/svelte.config.js create mode 100644 svelte-placeholder/tsconfig.json create mode 100644 svelte-placeholder/tsconfig.node.json create mode 100644 svelte-placeholder/vite.config.ts create mode 100644 svelte-readonly/.gitignore create mode 100644 svelte-readonly/README.md create mode 100644 svelte-readonly/index.html create mode 100644 svelte-readonly/package.json create mode 100644 svelte-readonly/src/App.svelte create mode 100644 svelte-readonly/src/app.css create mode 100644 svelte-readonly/src/components/editor/examples/readonly/editor.svelte create mode 100644 svelte-readonly/src/components/editor/examples/readonly/extension.ts create mode 100644 svelte-readonly/src/components/editor/examples/readonly/index.ts create mode 100644 svelte-readonly/src/components/editor/examples/readonly/toolbar.svelte create mode 100644 svelte-readonly/src/components/editor/sample/sample-doc-readonly.ts create mode 100644 svelte-readonly/src/components/editor/ui/button/button.svelte create mode 100644 svelte-readonly/src/components/editor/ui/button/index.ts create mode 100644 svelte-readonly/src/main.ts create mode 100644 svelte-readonly/src/vite-env.d.ts create mode 100644 svelte-readonly/svelte.config.js create mode 100644 svelte-readonly/tsconfig.json create mode 100644 svelte-readonly/tsconfig.node.json create mode 100644 svelte-readonly/vite.config.ts create mode 100644 svelte-rtl/.gitignore create mode 100644 svelte-rtl/README.md create mode 100644 svelte-rtl/index.html create mode 100644 svelte-rtl/package.json create mode 100644 svelte-rtl/src/App.svelte create mode 100644 svelte-rtl/src/app.css create mode 100644 svelte-rtl/src/components/editor/examples/rtl/editor.svelte create mode 100644 svelte-rtl/src/components/editor/examples/rtl/index.ts create mode 100644 svelte-rtl/src/components/editor/sample/sample-doc-rtl.ts create mode 100644 svelte-rtl/src/components/editor/sample/sample-uploader.ts create mode 100644 svelte-rtl/src/components/editor/ui/block-handle/block-handle.svelte create mode 100644 svelte-rtl/src/components/editor/ui/block-handle/index.ts create mode 100644 svelte-rtl/src/components/editor/ui/button/button.svelte create mode 100644 svelte-rtl/src/components/editor/ui/button/index.ts create mode 100644 svelte-rtl/src/components/editor/ui/drop-indicator/drop-indicator.svelte create mode 100644 svelte-rtl/src/components/editor/ui/drop-indicator/index.ts create mode 100644 svelte-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-rtl/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-rtl/src/components/editor/ui/inline-menu/index.ts create mode 100644 svelte-rtl/src/components/editor/ui/inline-menu/inline-menu.svelte create mode 100644 svelte-rtl/src/components/editor/ui/slash-menu/index.ts create mode 100644 svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.svelte create mode 100644 svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-item.svelte create mode 100644 svelte-rtl/src/components/editor/ui/slash-menu/slash-menu.svelte create mode 100644 svelte-rtl/src/components/editor/ui/table-handle/index.ts create mode 100644 svelte-rtl/src/components/editor/ui/table-handle/table-handle.svelte create mode 100644 svelte-rtl/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-rtl/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-rtl/src/main.ts create mode 100644 svelte-rtl/src/vite-env.d.ts create mode 100644 svelte-rtl/svelte.config.js create mode 100644 svelte-rtl/tsconfig.json create mode 100644 svelte-rtl/tsconfig.node.json create mode 100644 svelte-rtl/vite.config.ts create mode 100644 svelte-save-html/.gitignore create mode 100644 svelte-save-html/README.md create mode 100644 svelte-save-html/index.html create mode 100644 svelte-save-html/package.json create mode 100644 svelte-save-html/src/App.svelte create mode 100644 svelte-save-html/src/app.css create mode 100644 svelte-save-html/src/components/editor/examples/save-html/editor.svelte create mode 100644 svelte-save-html/src/components/editor/examples/save-html/index.ts create mode 100644 svelte-save-html/src/main.ts create mode 100644 svelte-save-html/src/vite-env.d.ts create mode 100644 svelte-save-html/svelte.config.js create mode 100644 svelte-save-html/tsconfig.json create mode 100644 svelte-save-html/tsconfig.node.json create mode 100644 svelte-save-html/vite.config.ts create mode 100644 svelte-save-json/.gitignore create mode 100644 svelte-save-json/README.md create mode 100644 svelte-save-json/index.html create mode 100644 svelte-save-json/package.json create mode 100644 svelte-save-json/src/App.svelte create mode 100644 svelte-save-json/src/app.css create mode 100644 svelte-save-json/src/components/editor/examples/save-json/editor.svelte create mode 100644 svelte-save-json/src/components/editor/examples/save-json/index.ts create mode 100644 svelte-save-json/src/main.ts create mode 100644 svelte-save-json/src/vite-env.d.ts create mode 100644 svelte-save-json/svelte.config.js create mode 100644 svelte-save-json/tsconfig.json create mode 100644 svelte-save-json/tsconfig.node.json create mode 100644 svelte-save-json/vite.config.ts create mode 100644 svelte-save-markdown/.gitignore create mode 100644 svelte-save-markdown/README.md create mode 100644 svelte-save-markdown/index.html create mode 100644 svelte-save-markdown/package.json create mode 100644 svelte-save-markdown/src/App.svelte create mode 100644 svelte-save-markdown/src/app.css create mode 100644 svelte-save-markdown/src/components/editor/examples/save-markdown/editor.svelte create mode 100644 svelte-save-markdown/src/components/editor/examples/save-markdown/index.ts create mode 100644 svelte-save-markdown/src/components/editor/examples/save-markdown/markdown.ts create mode 100644 svelte-save-markdown/src/main.ts create mode 100644 svelte-save-markdown/src/vite-env.d.ts create mode 100644 svelte-save-markdown/svelte.config.js create mode 100644 svelte-save-markdown/tsconfig.json create mode 100644 svelte-save-markdown/tsconfig.node.json create mode 100644 svelte-save-markdown/vite.config.ts create mode 100644 svelte-search/.gitignore create mode 100644 svelte-search/README.md create mode 100644 svelte-search/index.html create mode 100644 svelte-search/package.json create mode 100644 svelte-search/src/App.svelte create mode 100644 svelte-search/src/app.css create mode 100644 svelte-search/src/components/editor/examples/search/editor.svelte create mode 100644 svelte-search/src/components/editor/examples/search/extension.ts create mode 100644 svelte-search/src/components/editor/examples/search/index.ts create mode 100644 svelte-search/src/components/editor/sample/sample-doc-search.ts create mode 100644 svelte-search/src/components/editor/ui/button/button.svelte create mode 100644 svelte-search/src/components/editor/ui/button/index.ts create mode 100644 svelte-search/src/components/editor/ui/search/index.ts create mode 100644 svelte-search/src/components/editor/ui/search/search.svelte create mode 100644 svelte-search/src/main.ts create mode 100644 svelte-search/src/vite-env.d.ts create mode 100644 svelte-search/svelte.config.js create mode 100644 svelte-search/tsconfig.json create mode 100644 svelte-search/tsconfig.node.json create mode 100644 svelte-search/vite.config.ts create mode 100644 svelte-slash-menu/.gitignore create mode 100644 svelte-slash-menu/README.md create mode 100644 svelte-slash-menu/index.html create mode 100644 svelte-slash-menu/package.json create mode 100644 svelte-slash-menu/src/App.svelte create mode 100644 svelte-slash-menu/src/app.css create mode 100644 svelte-slash-menu/src/components/editor/examples/slash-menu/editor.svelte create mode 100644 svelte-slash-menu/src/components/editor/examples/slash-menu/extension.ts create mode 100644 svelte-slash-menu/src/components/editor/examples/slash-menu/index.ts create mode 100644 svelte-slash-menu/src/components/editor/ui/slash-menu/index.ts create mode 100644 svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.svelte create mode 100644 svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.svelte create mode 100644 svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu.svelte create mode 100644 svelte-slash-menu/src/main.ts create mode 100644 svelte-slash-menu/src/vite-env.d.ts create mode 100644 svelte-slash-menu/svelte.config.js create mode 100644 svelte-slash-menu/tsconfig.json create mode 100644 svelte-slash-menu/tsconfig.node.json create mode 100644 svelte-slash-menu/vite.config.ts create mode 100644 svelte-strike/.gitignore create mode 100644 svelte-strike/README.md create mode 100644 svelte-strike/index.html create mode 100644 svelte-strike/package.json create mode 100644 svelte-strike/src/App.svelte create mode 100644 svelte-strike/src/app.css create mode 100644 svelte-strike/src/components/editor/examples/strike/editor.svelte create mode 100644 svelte-strike/src/components/editor/examples/strike/extension.ts create mode 100644 svelte-strike/src/components/editor/examples/strike/index.ts create mode 100644 svelte-strike/src/components/editor/examples/strike/toolbar.svelte create mode 100644 svelte-strike/src/components/editor/sample/sample-doc-strike.ts create mode 100644 svelte-strike/src/components/editor/ui/button/button.svelte create mode 100644 svelte-strike/src/components/editor/ui/button/index.ts create mode 100644 svelte-strike/src/main.ts create mode 100644 svelte-strike/src/vite-env.d.ts create mode 100644 svelte-strike/svelte.config.js create mode 100644 svelte-strike/tsconfig.json create mode 100644 svelte-strike/tsconfig.node.json create mode 100644 svelte-strike/vite.config.ts create mode 100644 svelte-sub-sup/.gitignore create mode 100644 svelte-sub-sup/README.md create mode 100644 svelte-sub-sup/index.html create mode 100644 svelte-sub-sup/package.json create mode 100644 svelte-sub-sup/src/App.svelte create mode 100644 svelte-sub-sup/src/app.css create mode 100644 svelte-sub-sup/src/components/editor/examples/sub-sup/editor.svelte create mode 100644 svelte-sub-sup/src/components/editor/examples/sub-sup/extension.ts create mode 100644 svelte-sub-sup/src/components/editor/examples/sub-sup/index.ts create mode 100644 svelte-sub-sup/src/components/editor/examples/sub-sup/toolbar.svelte create mode 100644 svelte-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts create mode 100644 svelte-sub-sup/src/components/editor/ui/button/button.svelte create mode 100644 svelte-sub-sup/src/components/editor/ui/button/index.ts create mode 100644 svelte-sub-sup/src/main.ts create mode 100644 svelte-sub-sup/src/vite-env.d.ts create mode 100644 svelte-sub-sup/svelte.config.js create mode 100644 svelte-sub-sup/tsconfig.json create mode 100644 svelte-sub-sup/tsconfig.node.json create mode 100644 svelte-sub-sup/vite.config.ts create mode 100644 svelte-table/.gitignore create mode 100644 svelte-table/README.md create mode 100644 svelte-table/index.html create mode 100644 svelte-table/package.json create mode 100644 svelte-table/src/App.svelte create mode 100644 svelte-table/src/app.css create mode 100644 svelte-table/src/components/editor/examples/table/editor.svelte create mode 100644 svelte-table/src/components/editor/examples/table/extension.ts create mode 100644 svelte-table/src/components/editor/examples/table/index.ts create mode 100644 svelte-table/src/components/editor/sample/sample-doc-table.ts create mode 100644 svelte-table/src/components/editor/ui/table-handle/index.ts create mode 100644 svelte-table/src/components/editor/ui/table-handle/table-handle.svelte create mode 100644 svelte-table/src/main.ts create mode 100644 svelte-table/src/vite-env.d.ts create mode 100644 svelte-table/svelte.config.js create mode 100644 svelte-table/tsconfig.json create mode 100644 svelte-table/tsconfig.node.json create mode 100644 svelte-table/vite.config.ts create mode 100644 svelte-text-align/.gitignore create mode 100644 svelte-text-align/README.md create mode 100644 svelte-text-align/index.html create mode 100644 svelte-text-align/package.json create mode 100644 svelte-text-align/src/App.svelte create mode 100644 svelte-text-align/src/app.css create mode 100644 svelte-text-align/src/components/editor/examples/text-align/editor.svelte create mode 100644 svelte-text-align/src/components/editor/examples/text-align/extension.ts create mode 100644 svelte-text-align/src/components/editor/examples/text-align/index.ts create mode 100644 svelte-text-align/src/components/editor/examples/text-align/toolbar.svelte create mode 100644 svelte-text-align/src/components/editor/sample/sample-doc-text-align.ts create mode 100644 svelte-text-align/src/components/editor/ui/button/button.svelte create mode 100644 svelte-text-align/src/components/editor/ui/button/index.ts create mode 100644 svelte-text-align/src/main.ts create mode 100644 svelte-text-align/src/vite-env.d.ts create mode 100644 svelte-text-align/svelte.config.js create mode 100644 svelte-text-align/tsconfig.json create mode 100644 svelte-text-align/tsconfig.node.json create mode 100644 svelte-text-align/vite.config.ts create mode 100644 svelte-text-color/.gitignore create mode 100644 svelte-text-color/README.md create mode 100644 svelte-text-color/index.html create mode 100644 svelte-text-color/package.json create mode 100644 svelte-text-color/src/App.svelte create mode 100644 svelte-text-color/src/app.css create mode 100644 svelte-text-color/src/components/editor/examples/text-color/editor.svelte create mode 100644 svelte-text-color/src/components/editor/examples/text-color/extension.ts create mode 100644 svelte-text-color/src/components/editor/examples/text-color/index.ts create mode 100644 svelte-text-color/src/components/editor/examples/text-color/inline-menu.svelte create mode 100644 svelte-text-color/src/components/editor/sample/sample-doc-text-color.ts create mode 100644 svelte-text-color/src/components/editor/ui/button/button.svelte create mode 100644 svelte-text-color/src/components/editor/ui/button/index.ts create mode 100644 svelte-text-color/src/main.ts create mode 100644 svelte-text-color/src/vite-env.d.ts create mode 100644 svelte-text-color/svelte.config.js create mode 100644 svelte-text-color/tsconfig.json create mode 100644 svelte-text-color/tsconfig.node.json create mode 100644 svelte-text-color/vite.config.ts create mode 100644 svelte-toolbar/.gitignore create mode 100644 svelte-toolbar/README.md create mode 100644 svelte-toolbar/index.html create mode 100644 svelte-toolbar/package.json create mode 100644 svelte-toolbar/src/App.svelte create mode 100644 svelte-toolbar/src/app.css create mode 100644 svelte-toolbar/src/components/editor/examples/toolbar/editor.svelte create mode 100644 svelte-toolbar/src/components/editor/examples/toolbar/extension.ts create mode 100644 svelte-toolbar/src/components/editor/examples/toolbar/index.ts create mode 100644 svelte-toolbar/src/components/editor/sample/sample-uploader.ts create mode 100644 svelte-toolbar/src/components/editor/ui/button/button.svelte create mode 100644 svelte-toolbar/src/components/editor/ui/button/index.ts create mode 100644 svelte-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-toolbar/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-toolbar/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-toolbar/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-toolbar/src/main.ts create mode 100644 svelte-toolbar/src/vite-env.d.ts create mode 100644 svelte-toolbar/svelte.config.js create mode 100644 svelte-toolbar/tsconfig.json create mode 100644 svelte-toolbar/tsconfig.node.json create mode 100644 svelte-toolbar/vite.config.ts create mode 100644 svelte-typography/.gitignore create mode 100644 svelte-typography/README.md create mode 100644 svelte-typography/index.html create mode 100644 svelte-typography/package.json create mode 100644 svelte-typography/src/App.svelte create mode 100644 svelte-typography/src/app.css create mode 100644 svelte-typography/src/components/editor/examples/typography/editor.svelte create mode 100644 svelte-typography/src/components/editor/examples/typography/extension.ts create mode 100644 svelte-typography/src/components/editor/examples/typography/index.ts create mode 100644 svelte-typography/src/components/editor/sample/katex.ts create mode 100644 svelte-typography/src/components/editor/sample/sample-doc-typography.ts create mode 100644 svelte-typography/src/components/editor/ui/block-handle/block-handle.svelte create mode 100644 svelte-typography/src/components/editor/ui/block-handle/index.ts create mode 100644 svelte-typography/src/components/editor/ui/drop-indicator/drop-indicator.svelte create mode 100644 svelte-typography/src/components/editor/ui/drop-indicator/index.ts create mode 100644 svelte-typography/src/main.ts create mode 100644 svelte-typography/src/vite-env.d.ts create mode 100644 svelte-typography/svelte.config.js create mode 100644 svelte-typography/tsconfig.json create mode 100644 svelte-typography/tsconfig.node.json create mode 100644 svelte-typography/vite.config.ts create mode 100644 svelte-underline/.gitignore create mode 100644 svelte-underline/README.md create mode 100644 svelte-underline/index.html create mode 100644 svelte-underline/package.json create mode 100644 svelte-underline/src/App.svelte create mode 100644 svelte-underline/src/app.css create mode 100644 svelte-underline/src/components/editor/examples/underline/editor.svelte create mode 100644 svelte-underline/src/components/editor/examples/underline/extension.ts create mode 100644 svelte-underline/src/components/editor/examples/underline/index.ts create mode 100644 svelte-underline/src/components/editor/sample/sample-doc-underline.ts create mode 100644 svelte-underline/src/components/editor/ui/button/button.svelte create mode 100644 svelte-underline/src/components/editor/ui/button/index.ts create mode 100644 svelte-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-underline/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-underline/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-underline/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-underline/src/main.ts create mode 100644 svelte-underline/src/vite-env.d.ts create mode 100644 svelte-underline/svelte.config.js create mode 100644 svelte-underline/tsconfig.json create mode 100644 svelte-underline/tsconfig.node.json create mode 100644 svelte-underline/vite.config.ts create mode 100644 svelte-unmount/.gitignore create mode 100644 svelte-unmount/README.md create mode 100644 svelte-unmount/index.html create mode 100644 svelte-unmount/package.json create mode 100644 svelte-unmount/src/App.svelte create mode 100644 svelte-unmount/src/app.css create mode 100644 svelte-unmount/src/components/editor/examples/unmount/editor-component.svelte create mode 100644 svelte-unmount/src/components/editor/examples/unmount/editor.svelte create mode 100644 svelte-unmount/src/components/editor/examples/unmount/extension-component.svelte create mode 100644 svelte-unmount/src/components/editor/examples/unmount/index.ts create mode 100644 svelte-unmount/src/components/editor/ui/button/button.svelte create mode 100644 svelte-unmount/src/components/editor/ui/button/index.ts create mode 100644 svelte-unmount/src/components/editor/ui/inline-menu/index.ts create mode 100644 svelte-unmount/src/components/editor/ui/inline-menu/inline-menu.svelte create mode 100644 svelte-unmount/src/main.ts create mode 100644 svelte-unmount/src/vite-env.d.ts create mode 100644 svelte-unmount/svelte.config.js create mode 100644 svelte-unmount/tsconfig.json create mode 100644 svelte-unmount/tsconfig.node.json create mode 100644 svelte-unmount/vite.config.ts create mode 100644 svelte-user-menu-dynamic/.gitignore create mode 100644 svelte-user-menu-dynamic/README.md create mode 100644 svelte-user-menu-dynamic/index.html create mode 100644 svelte-user-menu-dynamic/package.json create mode 100644 svelte-user-menu-dynamic/src/App.svelte create mode 100644 svelte-user-menu-dynamic/src/app.css create mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.svelte create mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts create mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts create mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.svelte.ts create mode 100644 svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.svelte create mode 100644 svelte-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts create mode 100644 svelte-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts create mode 100644 svelte-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts create mode 100644 svelte-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.svelte create mode 100644 svelte-user-menu-dynamic/src/main.ts create mode 100644 svelte-user-menu-dynamic/src/vite-env.d.ts create mode 100644 svelte-user-menu-dynamic/svelte.config.js create mode 100644 svelte-user-menu-dynamic/tsconfig.json create mode 100644 svelte-user-menu-dynamic/tsconfig.node.json create mode 100644 svelte-user-menu-dynamic/vite.config.ts create mode 100644 svelte-user-menu/.gitignore create mode 100644 svelte-user-menu/README.md create mode 100644 svelte-user-menu/index.html create mode 100644 svelte-user-menu/package.json create mode 100644 svelte-user-menu/src/App.svelte create mode 100644 svelte-user-menu/src/app.css create mode 100644 svelte-user-menu/src/components/editor/examples/user-menu/editor.svelte create mode 100644 svelte-user-menu/src/components/editor/examples/user-menu/extension.ts create mode 100644 svelte-user-menu/src/components/editor/examples/user-menu/index.ts create mode 100644 svelte-user-menu/src/components/editor/sample/sample-tag-data.ts create mode 100644 svelte-user-menu/src/components/editor/sample/sample-user-data.ts create mode 100644 svelte-user-menu/src/components/editor/ui/tag-menu/index.ts create mode 100644 svelte-user-menu/src/components/editor/ui/tag-menu/tag-menu.svelte create mode 100644 svelte-user-menu/src/components/editor/ui/user-menu/index.ts create mode 100644 svelte-user-menu/src/components/editor/ui/user-menu/user-menu.svelte create mode 100644 svelte-user-menu/src/main.ts create mode 100644 svelte-user-menu/src/vite-env.d.ts create mode 100644 svelte-user-menu/svelte.config.js create mode 100644 svelte-user-menu/tsconfig.json create mode 100644 svelte-user-menu/tsconfig.node.json create mode 100644 svelte-user-menu/vite.config.ts create mode 100644 svelte-word-counter/.gitignore create mode 100644 svelte-word-counter/README.md create mode 100644 svelte-word-counter/index.html create mode 100644 svelte-word-counter/package.json create mode 100644 svelte-word-counter/src/App.svelte create mode 100644 svelte-word-counter/src/app.css create mode 100644 svelte-word-counter/src/components/editor/examples/word-counter/editor.svelte create mode 100644 svelte-word-counter/src/components/editor/examples/word-counter/extension.ts create mode 100644 svelte-word-counter/src/components/editor/examples/word-counter/index.ts create mode 100644 svelte-word-counter/src/components/editor/sample/sample-doc-word-counter.ts create mode 100644 svelte-word-counter/src/components/editor/ui/word-counter/index.ts create mode 100644 svelte-word-counter/src/components/editor/ui/word-counter/word-counter.svelte create mode 100644 svelte-word-counter/src/main.ts create mode 100644 svelte-word-counter/src/vite-env.d.ts create mode 100644 svelte-word-counter/svelte.config.js create mode 100644 svelte-word-counter/tsconfig.json create mode 100644 svelte-word-counter/tsconfig.node.json create mode 100644 svelte-word-counter/vite.config.ts create mode 100644 svelte-yjs/.gitignore create mode 100644 svelte-yjs/README.md create mode 100644 svelte-yjs/index.html create mode 100644 svelte-yjs/package.json create mode 100644 svelte-yjs/src/App.svelte create mode 100644 svelte-yjs/src/app.css create mode 100644 svelte-yjs/src/components/editor/examples/yjs/editor-component.svelte create mode 100644 svelte-yjs/src/components/editor/examples/yjs/editor.svelte create mode 100644 svelte-yjs/src/components/editor/examples/yjs/extension.ts create mode 100644 svelte-yjs/src/components/editor/examples/yjs/index.ts create mode 100644 svelte-yjs/src/components/editor/ui/button/button.svelte create mode 100644 svelte-yjs/src/components/editor/ui/button/index.ts create mode 100644 svelte-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 svelte-yjs/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 svelte-yjs/src/components/editor/ui/toolbar/index.ts create mode 100644 svelte-yjs/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 svelte-yjs/src/main.ts create mode 100644 svelte-yjs/src/vite-env.d.ts create mode 100644 svelte-yjs/svelte.config.js create mode 100644 svelte-yjs/tsconfig.json create mode 100644 svelte-yjs/tsconfig.node.json create mode 100644 svelte-yjs/vite.config.ts create mode 100644 sveltekit-full/.gitignore create mode 100644 sveltekit-full/README.md create mode 100644 sveltekit-full/package.json create mode 100644 sveltekit-full/src/app.css create mode 100644 sveltekit-full/src/app.d.ts create mode 100644 sveltekit-full/src/app.html create mode 100644 sveltekit-full/src/components/editor/examples/full/editor.svelte create mode 100644 sveltekit-full/src/components/editor/examples/full/extension.ts create mode 100644 sveltekit-full/src/components/editor/examples/full/index.ts create mode 100644 sveltekit-full/src/components/editor/sample/katex.ts create mode 100644 sveltekit-full/src/components/editor/sample/sample-doc-full.ts create mode 100644 sveltekit-full/src/components/editor/sample/sample-tag-data.ts create mode 100644 sveltekit-full/src/components/editor/sample/sample-uploader.ts create mode 100644 sveltekit-full/src/components/editor/sample/sample-user-data.ts create mode 100644 sveltekit-full/src/components/editor/ui/block-handle/block-handle.svelte create mode 100644 sveltekit-full/src/components/editor/ui/block-handle/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/button/button.svelte create mode 100644 sveltekit-full/src/components/editor/ui/button/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/code-block-view/code-block-view.svelte create mode 100644 sveltekit-full/src/components/editor/ui/code-block-view/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte create mode 100644 sveltekit-full/src/components/editor/ui/drop-indicator/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte create mode 100644 sveltekit-full/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/image-view/image-view.svelte create mode 100644 sveltekit-full/src/components/editor/ui/image-view/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/inline-menu/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/inline-menu/inline-menu.svelte create mode 100644 sveltekit-full/src/components/editor/ui/slash-menu/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte create mode 100644 sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte create mode 100644 sveltekit-full/src/components/editor/ui/slash-menu/slash-menu.svelte create mode 100644 sveltekit-full/src/components/editor/ui/table-handle/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/table-handle/table-handle.svelte create mode 100644 sveltekit-full/src/components/editor/ui/tag-menu/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/tag-menu/tag-menu.svelte create mode 100644 sveltekit-full/src/components/editor/ui/toolbar/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/toolbar/toolbar.svelte create mode 100644 sveltekit-full/src/components/editor/ui/user-menu/index.ts create mode 100644 sveltekit-full/src/components/editor/ui/user-menu/user-menu.svelte create mode 100644 sveltekit-full/src/lib/App.svelte create mode 100644 sveltekit-full/src/lib/client-only-editor.svelte create mode 100644 sveltekit-full/src/lib/editor.svelte create mode 100644 sveltekit-full/src/routes/+layout.svelte create mode 100644 sveltekit-full/src/routes/+page.svelte create mode 100644 sveltekit-full/static/favicon.png create mode 100644 sveltekit-full/svelte.config.js create mode 100644 sveltekit-full/tsconfig.json create mode 100644 sveltekit-full/vite.config.ts create mode 100644 vanilla-minimal/.gitignore create mode 100644 vanilla-minimal/README.md create mode 100644 vanilla-minimal/index.html create mode 100644 vanilla-minimal/package.json create mode 100644 vanilla-minimal/src/app.css create mode 100644 vanilla-minimal/src/components/editor/examples/minimal/editor.ts create mode 100644 vanilla-minimal/src/components/editor/examples/minimal/index.ts create mode 100644 vanilla-minimal/src/editor.ts create mode 100644 vanilla-minimal/src/main.ts create mode 100644 vanilla-minimal/tsconfig.json create mode 100644 vanilla-minimal/vite.config.ts create mode 100644 vanilla-slash-menu/.gitignore create mode 100644 vanilla-slash-menu/README.md create mode 100644 vanilla-slash-menu/index.html create mode 100644 vanilla-slash-menu/package.json create mode 100644 vanilla-slash-menu/src/app.css create mode 100644 vanilla-slash-menu/src/components/editor/examples/slash-menu/editor.ts create mode 100644 vanilla-slash-menu/src/components/editor/examples/slash-menu/extension.ts create mode 100644 vanilla-slash-menu/src/components/editor/examples/slash-menu/index.ts create mode 100644 vanilla-slash-menu/src/components/editor/ui/slash-menu/index.ts create mode 100644 vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts create mode 100644 vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts create mode 100644 vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts create mode 100644 vanilla-slash-menu/src/editor.ts create mode 100644 vanilla-slash-menu/src/main.ts create mode 100644 vanilla-slash-menu/tsconfig.json create mode 100644 vanilla-slash-menu/vite.config.ts create mode 100644 vue-block-handle/.gitignore create mode 100644 vue-block-handle/README.md create mode 100644 vue-block-handle/index.html create mode 100644 vue-block-handle/package.json create mode 100644 vue-block-handle/src/App.vue create mode 100644 vue-block-handle/src/app.css create mode 100644 vue-block-handle/src/components/editor/examples/block-handle/editor.vue create mode 100644 vue-block-handle/src/components/editor/examples/block-handle/extension.ts create mode 100644 vue-block-handle/src/components/editor/examples/block-handle/index.ts create mode 100644 vue-block-handle/src/components/editor/sample/sample-doc-block-handle.ts create mode 100644 vue-block-handle/src/components/editor/ui/block-handle/block-handle.vue create mode 100644 vue-block-handle/src/components/editor/ui/block-handle/index.ts create mode 100644 vue-block-handle/src/components/editor/ui/code-block-view/code-block-view.vue create mode 100644 vue-block-handle/src/components/editor/ui/code-block-view/index.ts create mode 100644 vue-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.vue create mode 100644 vue-block-handle/src/components/editor/ui/drop-indicator/index.ts create mode 100644 vue-block-handle/src/main.ts create mode 100644 vue-block-handle/tsconfig.app.json create mode 100644 vue-block-handle/tsconfig.json create mode 100644 vue-block-handle/tsconfig.node.json create mode 100644 vue-block-handle/vite.config.ts create mode 100644 vue-blockquote/.gitignore create mode 100644 vue-blockquote/README.md create mode 100644 vue-blockquote/index.html create mode 100644 vue-blockquote/package.json create mode 100644 vue-blockquote/src/App.vue create mode 100644 vue-blockquote/src/app.css create mode 100644 vue-blockquote/src/components/editor/examples/blockquote/editor.vue create mode 100644 vue-blockquote/src/components/editor/examples/blockquote/extension.ts create mode 100644 vue-blockquote/src/components/editor/examples/blockquote/index.ts create mode 100644 vue-blockquote/src/components/editor/ui/button/button.vue create mode 100644 vue-blockquote/src/components/editor/ui/button/index.ts create mode 100644 vue-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-blockquote/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-blockquote/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-blockquote/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-blockquote/src/main.ts create mode 100644 vue-blockquote/tsconfig.app.json create mode 100644 vue-blockquote/tsconfig.json create mode 100644 vue-blockquote/tsconfig.node.json create mode 100644 vue-blockquote/vite.config.ts create mode 100644 vue-bold/.gitignore create mode 100644 vue-bold/README.md create mode 100644 vue-bold/index.html create mode 100644 vue-bold/package.json create mode 100644 vue-bold/src/App.vue create mode 100644 vue-bold/src/app.css create mode 100644 vue-bold/src/components/editor/examples/bold/editor.vue create mode 100644 vue-bold/src/components/editor/examples/bold/extension.ts create mode 100644 vue-bold/src/components/editor/examples/bold/index.ts create mode 100644 vue-bold/src/components/editor/sample/sample-doc-bold.ts create mode 100644 vue-bold/src/components/editor/ui/button/button.vue create mode 100644 vue-bold/src/components/editor/ui/button/index.ts create mode 100644 vue-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-bold/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-bold/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-bold/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-bold/src/main.ts create mode 100644 vue-bold/tsconfig.app.json create mode 100644 vue-bold/tsconfig.json create mode 100644 vue-bold/tsconfig.node.json create mode 100644 vue-bold/vite.config.ts create mode 100644 vue-change-tracking/.gitignore create mode 100644 vue-change-tracking/README.md create mode 100644 vue-change-tracking/index.html create mode 100644 vue-change-tracking/package.json create mode 100644 vue-change-tracking/src/App.vue create mode 100644 vue-change-tracking/src/app.css create mode 100644 vue-change-tracking/src/components/editor/examples/change-tracking/editor-diff.vue create mode 100644 vue-change-tracking/src/components/editor/examples/change-tracking/editor-main.vue create mode 100644 vue-change-tracking/src/components/editor/examples/change-tracking/editor.vue create mode 100644 vue-change-tracking/src/components/editor/examples/change-tracking/index.ts create mode 100644 vue-change-tracking/src/main.ts create mode 100644 vue-change-tracking/tsconfig.app.json create mode 100644 vue-change-tracking/tsconfig.json create mode 100644 vue-change-tracking/tsconfig.node.json create mode 100644 vue-change-tracking/vite.config.ts create mode 100644 vue-code-block-themes/.gitignore create mode 100644 vue-code-block-themes/README.md create mode 100644 vue-code-block-themes/index.html create mode 100644 vue-code-block-themes/package.json create mode 100644 vue-code-block-themes/src/App.vue create mode 100644 vue-code-block-themes/src/app.css create mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/editor.vue create mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts create mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/index.ts create mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.vue create mode 100644 vue-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.vue create mode 100644 vue-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 vue-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.vue create mode 100644 vue-code-block-themes/src/components/editor/ui/code-block-view/index.ts create mode 100644 vue-code-block-themes/src/main.ts create mode 100644 vue-code-block-themes/tsconfig.app.json create mode 100644 vue-code-block-themes/tsconfig.json create mode 100644 vue-code-block-themes/tsconfig.node.json create mode 100644 vue-code-block-themes/vite.config.ts create mode 100644 vue-code-block/.gitignore create mode 100644 vue-code-block/README.md create mode 100644 vue-code-block/index.html create mode 100644 vue-code-block/package.json create mode 100644 vue-code-block/src/App.vue create mode 100644 vue-code-block/src/app.css create mode 100644 vue-code-block/src/components/editor/examples/code-block/editor.vue create mode 100644 vue-code-block/src/components/editor/examples/code-block/extension.ts create mode 100644 vue-code-block/src/components/editor/examples/code-block/index.ts create mode 100644 vue-code-block/src/components/editor/sample/sample-doc-code-block.ts create mode 100644 vue-code-block/src/components/editor/ui/button/button.vue create mode 100644 vue-code-block/src/components/editor/ui/button/index.ts create mode 100644 vue-code-block/src/components/editor/ui/code-block-view/code-block-view.vue create mode 100644 vue-code-block/src/components/editor/ui/code-block-view/index.ts create mode 100644 vue-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-code-block/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-code-block/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-code-block/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-code-block/src/main.ts create mode 100644 vue-code-block/tsconfig.app.json create mode 100644 vue-code-block/tsconfig.json create mode 100644 vue-code-block/tsconfig.node.json create mode 100644 vue-code-block/vite.config.ts create mode 100644 vue-code/.gitignore create mode 100644 vue-code/README.md create mode 100644 vue-code/index.html create mode 100644 vue-code/package.json create mode 100644 vue-code/src/App.vue create mode 100644 vue-code/src/app.css create mode 100644 vue-code/src/components/editor/examples/code/editor.vue create mode 100644 vue-code/src/components/editor/examples/code/extension.ts create mode 100644 vue-code/src/components/editor/examples/code/index.ts create mode 100644 vue-code/src/components/editor/sample/sample-doc-code.ts create mode 100644 vue-code/src/components/editor/ui/button/button.vue create mode 100644 vue-code/src/components/editor/ui/button/index.ts create mode 100644 vue-code/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-code/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-code/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-code/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-code/src/main.ts create mode 100644 vue-code/tsconfig.app.json create mode 100644 vue-code/tsconfig.json create mode 100644 vue-code/tsconfig.node.json create mode 100644 vue-code/vite.config.ts create mode 100644 vue-drop-cursor/.gitignore create mode 100644 vue-drop-cursor/README.md create mode 100644 vue-drop-cursor/index.html create mode 100644 vue-drop-cursor/package.json create mode 100644 vue-drop-cursor/src/App.vue create mode 100644 vue-drop-cursor/src/app.css create mode 100644 vue-drop-cursor/src/components/editor/examples/drop-cursor/editor.vue create mode 100644 vue-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts create mode 100644 vue-drop-cursor/src/components/editor/examples/drop-cursor/index.ts create mode 100644 vue-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts create mode 100644 vue-drop-cursor/src/main.ts create mode 100644 vue-drop-cursor/tsconfig.app.json create mode 100644 vue-drop-cursor/tsconfig.json create mode 100644 vue-drop-cursor/tsconfig.node.json create mode 100644 vue-drop-cursor/vite.config.ts create mode 100644 vue-emoji-rules/.gitignore create mode 100644 vue-emoji-rules/README.md create mode 100644 vue-emoji-rules/index.html create mode 100644 vue-emoji-rules/package.json create mode 100644 vue-emoji-rules/src/App.vue create mode 100644 vue-emoji-rules/src/app.css create mode 100644 vue-emoji-rules/src/components/editor/examples/emoji-rules/editor.vue create mode 100644 vue-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts create mode 100644 vue-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts create mode 100644 vue-emoji-rules/src/components/editor/examples/emoji-rules/index.ts create mode 100644 vue-emoji-rules/src/main.ts create mode 100644 vue-emoji-rules/tsconfig.app.json create mode 100644 vue-emoji-rules/tsconfig.json create mode 100644 vue-emoji-rules/tsconfig.node.json create mode 100644 vue-emoji-rules/vite.config.ts create mode 100644 vue-full/.gitignore create mode 100644 vue-full/README.md create mode 100644 vue-full/index.html create mode 100644 vue-full/package.json create mode 100644 vue-full/src/App.vue create mode 100644 vue-full/src/app.css create mode 100644 vue-full/src/components/editor/examples/full/editor.vue create mode 100644 vue-full/src/components/editor/examples/full/extension.ts create mode 100644 vue-full/src/components/editor/examples/full/index.ts create mode 100644 vue-full/src/components/editor/sample/katex.ts create mode 100644 vue-full/src/components/editor/sample/sample-doc-full.ts create mode 100644 vue-full/src/components/editor/sample/sample-tag-data.ts create mode 100644 vue-full/src/components/editor/sample/sample-uploader.ts create mode 100644 vue-full/src/components/editor/sample/sample-user-data.ts create mode 100644 vue-full/src/components/editor/ui/block-handle/block-handle.vue create mode 100644 vue-full/src/components/editor/ui/block-handle/index.ts create mode 100644 vue-full/src/components/editor/ui/button/button.vue create mode 100644 vue-full/src/components/editor/ui/button/index.ts create mode 100644 vue-full/src/components/editor/ui/code-block-view/code-block-view.vue create mode 100644 vue-full/src/components/editor/ui/code-block-view/index.ts create mode 100644 vue-full/src/components/editor/ui/drop-indicator/drop-indicator.vue create mode 100644 vue-full/src/components/editor/ui/drop-indicator/index.ts create mode 100644 vue-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-full/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-full/src/components/editor/ui/image-view/image-view.vue create mode 100644 vue-full/src/components/editor/ui/image-view/index.ts create mode 100644 vue-full/src/components/editor/ui/inline-menu/index.ts create mode 100644 vue-full/src/components/editor/ui/inline-menu/inline-menu.vue create mode 100644 vue-full/src/components/editor/ui/slash-menu/index.ts create mode 100644 vue-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue create mode 100644 vue-full/src/components/editor/ui/slash-menu/slash-menu-item.vue create mode 100644 vue-full/src/components/editor/ui/slash-menu/slash-menu.vue create mode 100644 vue-full/src/components/editor/ui/table-handle/index.ts create mode 100644 vue-full/src/components/editor/ui/table-handle/table-handle.vue create mode 100644 vue-full/src/components/editor/ui/tag-menu/index.ts create mode 100644 vue-full/src/components/editor/ui/tag-menu/tag-menu.vue create mode 100644 vue-full/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-full/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-full/src/components/editor/ui/user-menu/index.ts create mode 100644 vue-full/src/components/editor/ui/user-menu/user-menu.vue create mode 100644 vue-full/src/main.ts create mode 100644 vue-full/tsconfig.app.json create mode 100644 vue-full/tsconfig.json create mode 100644 vue-full/tsconfig.node.json create mode 100644 vue-full/vite.config.ts create mode 100644 vue-gap-cursor/.gitignore create mode 100644 vue-gap-cursor/README.md create mode 100644 vue-gap-cursor/index.html create mode 100644 vue-gap-cursor/package.json create mode 100644 vue-gap-cursor/src/App.vue create mode 100644 vue-gap-cursor/src/app.css create mode 100644 vue-gap-cursor/src/components/editor/examples/gap-cursor/editor.vue create mode 100644 vue-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts create mode 100644 vue-gap-cursor/src/components/editor/examples/gap-cursor/index.ts create mode 100644 vue-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts create mode 100644 vue-gap-cursor/src/main.ts create mode 100644 vue-gap-cursor/tsconfig.app.json create mode 100644 vue-gap-cursor/tsconfig.json create mode 100644 vue-gap-cursor/tsconfig.node.json create mode 100644 vue-gap-cursor/vite.config.ts create mode 100644 vue-hard-break/.gitignore create mode 100644 vue-hard-break/README.md create mode 100644 vue-hard-break/index.html create mode 100644 vue-hard-break/package.json create mode 100644 vue-hard-break/src/App.vue create mode 100644 vue-hard-break/src/app.css create mode 100644 vue-hard-break/src/components/editor/examples/hard-break/editor.vue create mode 100644 vue-hard-break/src/components/editor/examples/hard-break/extension.ts create mode 100644 vue-hard-break/src/components/editor/examples/hard-break/index.ts create mode 100644 vue-hard-break/src/components/editor/examples/hard-break/toolbar.vue create mode 100644 vue-hard-break/src/components/editor/sample/sample-doc-hard-break.ts create mode 100644 vue-hard-break/src/components/editor/ui/button/button.vue create mode 100644 vue-hard-break/src/components/editor/ui/button/index.ts create mode 100644 vue-hard-break/src/main.ts create mode 100644 vue-hard-break/tsconfig.app.json create mode 100644 vue-hard-break/tsconfig.json create mode 100644 vue-hard-break/tsconfig.node.json create mode 100644 vue-hard-break/vite.config.ts create mode 100644 vue-heading/.gitignore create mode 100644 vue-heading/README.md create mode 100644 vue-heading/index.html create mode 100644 vue-heading/package.json create mode 100644 vue-heading/src/App.vue create mode 100644 vue-heading/src/app.css create mode 100644 vue-heading/src/components/editor/examples/heading/editor.vue create mode 100644 vue-heading/src/components/editor/examples/heading/extension.ts create mode 100644 vue-heading/src/components/editor/examples/heading/index.ts create mode 100644 vue-heading/src/components/editor/sample/sample-doc-heading.ts create mode 100644 vue-heading/src/components/editor/ui/button/button.vue create mode 100644 vue-heading/src/components/editor/ui/button/index.ts create mode 100644 vue-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-heading/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-heading/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-heading/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-heading/src/main.ts create mode 100644 vue-heading/tsconfig.app.json create mode 100644 vue-heading/tsconfig.json create mode 100644 vue-heading/tsconfig.node.json create mode 100644 vue-heading/vite.config.ts create mode 100644 vue-highlight/.gitignore create mode 100644 vue-highlight/README.md create mode 100644 vue-highlight/index.html create mode 100644 vue-highlight/package.json create mode 100644 vue-highlight/src/App.vue create mode 100644 vue-highlight/src/app.css create mode 100644 vue-highlight/src/components/editor/examples/highlight/editor.vue create mode 100644 vue-highlight/src/components/editor/examples/highlight/extension.ts create mode 100644 vue-highlight/src/components/editor/examples/highlight/index.ts create mode 100644 vue-highlight/src/components/editor/examples/highlight/toolbar.vue create mode 100644 vue-highlight/src/components/editor/sample/sample-doc-highlight.ts create mode 100644 vue-highlight/src/components/editor/ui/button/button.vue create mode 100644 vue-highlight/src/components/editor/ui/button/index.ts create mode 100644 vue-highlight/src/main.ts create mode 100644 vue-highlight/tsconfig.app.json create mode 100644 vue-highlight/tsconfig.json create mode 100644 vue-highlight/tsconfig.node.json create mode 100644 vue-highlight/vite.config.ts create mode 100644 vue-horizontal-rule/.gitignore create mode 100644 vue-horizontal-rule/README.md create mode 100644 vue-horizontal-rule/index.html create mode 100644 vue-horizontal-rule/package.json create mode 100644 vue-horizontal-rule/src/App.vue create mode 100644 vue-horizontal-rule/src/app.css create mode 100644 vue-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.vue create mode 100644 vue-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts create mode 100644 vue-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts create mode 100644 vue-horizontal-rule/src/components/editor/ui/button/button.vue create mode 100644 vue-horizontal-rule/src/components/editor/ui/button/index.ts create mode 100644 vue-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-horizontal-rule/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-horizontal-rule/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-horizontal-rule/src/main.ts create mode 100644 vue-horizontal-rule/tsconfig.app.json create mode 100644 vue-horizontal-rule/tsconfig.json create mode 100644 vue-horizontal-rule/tsconfig.node.json create mode 100644 vue-horizontal-rule/vite.config.ts create mode 100644 vue-image-view/.gitignore create mode 100644 vue-image-view/README.md create mode 100644 vue-image-view/index.html create mode 100644 vue-image-view/package.json create mode 100644 vue-image-view/src/App.vue create mode 100644 vue-image-view/src/app.css create mode 100644 vue-image-view/src/components/editor/examples/image-view/editor.vue create mode 100644 vue-image-view/src/components/editor/examples/image-view/extension.ts create mode 100644 vue-image-view/src/components/editor/examples/image-view/index.ts create mode 100644 vue-image-view/src/components/editor/sample/sample-doc-image.ts create mode 100644 vue-image-view/src/components/editor/sample/sample-uploader.ts create mode 100644 vue-image-view/src/components/editor/ui/image-view/image-view.vue create mode 100644 vue-image-view/src/components/editor/ui/image-view/index.ts create mode 100644 vue-image-view/src/main.ts create mode 100644 vue-image-view/tsconfig.app.json create mode 100644 vue-image-view/tsconfig.json create mode 100644 vue-image-view/tsconfig.node.json create mode 100644 vue-image-view/vite.config.ts create mode 100644 vue-inline-menu/.gitignore create mode 100644 vue-inline-menu/README.md create mode 100644 vue-inline-menu/index.html create mode 100644 vue-inline-menu/package.json create mode 100644 vue-inline-menu/src/App.vue create mode 100644 vue-inline-menu/src/app.css create mode 100644 vue-inline-menu/src/components/editor/examples/inline-menu/editor.vue create mode 100644 vue-inline-menu/src/components/editor/examples/inline-menu/extension.ts create mode 100644 vue-inline-menu/src/components/editor/examples/inline-menu/index.ts create mode 100644 vue-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts create mode 100644 vue-inline-menu/src/components/editor/ui/button/button.vue create mode 100644 vue-inline-menu/src/components/editor/ui/button/index.ts create mode 100644 vue-inline-menu/src/components/editor/ui/inline-menu/index.ts create mode 100644 vue-inline-menu/src/components/editor/ui/inline-menu/inline-menu.vue create mode 100644 vue-inline-menu/src/main.ts create mode 100644 vue-inline-menu/tsconfig.app.json create mode 100644 vue-inline-menu/tsconfig.json create mode 100644 vue-inline-menu/tsconfig.node.json create mode 100644 vue-inline-menu/vite.config.ts create mode 100644 vue-italic/.gitignore create mode 100644 vue-italic/README.md create mode 100644 vue-italic/index.html create mode 100644 vue-italic/package.json create mode 100644 vue-italic/src/App.vue create mode 100644 vue-italic/src/app.css create mode 100644 vue-italic/src/components/editor/examples/italic/editor.vue create mode 100644 vue-italic/src/components/editor/examples/italic/extension.ts create mode 100644 vue-italic/src/components/editor/examples/italic/index.ts create mode 100644 vue-italic/src/components/editor/sample/sample-doc-italic.ts create mode 100644 vue-italic/src/components/editor/ui/button/button.vue create mode 100644 vue-italic/src/components/editor/ui/button/index.ts create mode 100644 vue-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-italic/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-italic/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-italic/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-italic/src/main.ts create mode 100644 vue-italic/tsconfig.app.json create mode 100644 vue-italic/tsconfig.json create mode 100644 vue-italic/tsconfig.node.json create mode 100644 vue-italic/vite.config.ts create mode 100644 vue-katex/.gitignore create mode 100644 vue-katex/README.md create mode 100644 vue-katex/index.html create mode 100644 vue-katex/package.json create mode 100644 vue-katex/src/App.vue create mode 100644 vue-katex/src/app.css create mode 100644 vue-katex/src/components/editor/examples/katex/editor.vue create mode 100644 vue-katex/src/components/editor/examples/katex/extension.ts create mode 100644 vue-katex/src/components/editor/examples/katex/index.ts create mode 100644 vue-katex/src/components/editor/sample/katex.ts create mode 100644 vue-katex/src/components/editor/sample/sample-doc-tex.ts create mode 100644 vue-katex/src/main.ts create mode 100644 vue-katex/tsconfig.app.json create mode 100644 vue-katex/tsconfig.json create mode 100644 vue-katex/tsconfig.node.json create mode 100644 vue-katex/vite.config.ts create mode 100644 vue-keymap/.gitignore create mode 100644 vue-keymap/README.md create mode 100644 vue-keymap/index.html create mode 100644 vue-keymap/package.json create mode 100644 vue-keymap/src/App.vue create mode 100644 vue-keymap/src/app.css create mode 100644 vue-keymap/src/components/editor/examples/keymap/editor.vue create mode 100644 vue-keymap/src/components/editor/examples/keymap/extension.ts create mode 100644 vue-keymap/src/components/editor/examples/keymap/index.ts create mode 100644 vue-keymap/src/components/editor/examples/keymap/toolbar.vue create mode 100644 vue-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts create mode 100644 vue-keymap/src/components/editor/ui/button/button.vue create mode 100644 vue-keymap/src/components/editor/ui/button/index.ts create mode 100644 vue-keymap/src/main.ts create mode 100644 vue-keymap/tsconfig.app.json create mode 100644 vue-keymap/tsconfig.json create mode 100644 vue-keymap/tsconfig.node.json create mode 100644 vue-keymap/vite.config.ts create mode 100644 vue-link-mark-view/.gitignore create mode 100644 vue-link-mark-view/README.md create mode 100644 vue-link-mark-view/index.html create mode 100644 vue-link-mark-view/package.json create mode 100644 vue-link-mark-view/src/App.vue create mode 100644 vue-link-mark-view/src/app.css create mode 100644 vue-link-mark-view/src/components/editor/examples/link-mark-view/editor.vue create mode 100644 vue-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts create mode 100644 vue-link-mark-view/src/components/editor/examples/link-mark-view/index.ts create mode 100644 vue-link-mark-view/src/components/editor/examples/link-mark-view/link-view.vue create mode 100644 vue-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts create mode 100644 vue-link-mark-view/src/main.ts create mode 100644 vue-link-mark-view/tsconfig.app.json create mode 100644 vue-link-mark-view/tsconfig.json create mode 100644 vue-link-mark-view/tsconfig.node.json create mode 100644 vue-link-mark-view/vite.config.ts create mode 100644 vue-link/.gitignore create mode 100644 vue-link/README.md create mode 100644 vue-link/index.html create mode 100644 vue-link/package.json create mode 100644 vue-link/src/App.vue create mode 100644 vue-link/src/app.css create mode 100644 vue-link/src/components/editor/examples/link/editor.vue create mode 100644 vue-link/src/components/editor/examples/link/extension.ts create mode 100644 vue-link/src/components/editor/examples/link/index.ts create mode 100644 vue-link/src/components/editor/sample/sample-doc-link.ts create mode 100644 vue-link/src/components/editor/ui/button/button.vue create mode 100644 vue-link/src/components/editor/ui/button/index.ts create mode 100644 vue-link/src/components/editor/ui/inline-menu/index.ts create mode 100644 vue-link/src/components/editor/ui/inline-menu/inline-menu.vue create mode 100644 vue-link/src/main.ts create mode 100644 vue-link/tsconfig.app.json create mode 100644 vue-link/tsconfig.json create mode 100644 vue-link/tsconfig.node.json create mode 100644 vue-link/vite.config.ts create mode 100644 vue-list-custom-checkbox/.gitignore create mode 100644 vue-list-custom-checkbox/README.md create mode 100644 vue-list-custom-checkbox/index.html create mode 100644 vue-list-custom-checkbox/package.json create mode 100644 vue-list-custom-checkbox/src/App.vue create mode 100644 vue-list-custom-checkbox/src/app.css create mode 100644 vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css create mode 100644 vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.vue create mode 100644 vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts create mode 100644 vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts create mode 100644 vue-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts create mode 100644 vue-list-custom-checkbox/src/components/editor/ui/button/button.vue create mode 100644 vue-list-custom-checkbox/src/components/editor/ui/button/index.ts create mode 100644 vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-list-custom-checkbox/src/main.ts create mode 100644 vue-list-custom-checkbox/tsconfig.app.json create mode 100644 vue-list-custom-checkbox/tsconfig.json create mode 100644 vue-list-custom-checkbox/tsconfig.node.json create mode 100644 vue-list-custom-checkbox/vite.config.ts create mode 100644 vue-list/.gitignore create mode 100644 vue-list/README.md create mode 100644 vue-list/index.html create mode 100644 vue-list/package.json create mode 100644 vue-list/src/App.vue create mode 100644 vue-list/src/app.css create mode 100644 vue-list/src/components/editor/examples/list/editor.vue create mode 100644 vue-list/src/components/editor/examples/list/extension.ts create mode 100644 vue-list/src/components/editor/examples/list/index.ts create mode 100644 vue-list/src/components/editor/sample/sample-doc-list.ts create mode 100644 vue-list/src/components/editor/ui/button/button.vue create mode 100644 vue-list/src/components/editor/ui/button/index.ts create mode 100644 vue-list/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-list/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-list/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-list/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-list/src/main.ts create mode 100644 vue-list/tsconfig.app.json create mode 100644 vue-list/tsconfig.json create mode 100644 vue-list/tsconfig.node.json create mode 100644 vue-list/vite.config.ts create mode 100644 vue-loro/.gitignore create mode 100644 vue-loro/README.md create mode 100644 vue-loro/index.html create mode 100644 vue-loro/package.json create mode 100644 vue-loro/src/App.vue create mode 100644 vue-loro/src/app.css create mode 100644 vue-loro/src/components/editor/examples/loro/editor-component.vue create mode 100644 vue-loro/src/components/editor/examples/loro/editor.vue create mode 100644 vue-loro/src/components/editor/examples/loro/extension.ts create mode 100644 vue-loro/src/components/editor/examples/loro/index.ts create mode 100644 vue-loro/src/components/editor/ui/button/button.vue create mode 100644 vue-loro/src/components/editor/ui/button/index.ts create mode 100644 vue-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-loro/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-loro/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-loro/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-loro/src/main.ts create mode 100644 vue-loro/tsconfig.app.json create mode 100644 vue-loro/tsconfig.json create mode 100644 vue-loro/tsconfig.node.json create mode 100644 vue-loro/vite.config.ts create mode 100644 vue-mark-rule/.gitignore create mode 100644 vue-mark-rule/README.md create mode 100644 vue-mark-rule/index.html create mode 100644 vue-mark-rule/package.json create mode 100644 vue-mark-rule/src/App.vue create mode 100644 vue-mark-rule/src/app.css create mode 100644 vue-mark-rule/src/components/editor/examples/mark-rule/editor.vue create mode 100644 vue-mark-rule/src/components/editor/examples/mark-rule/extension.ts create mode 100644 vue-mark-rule/src/components/editor/examples/mark-rule/index.ts create mode 100644 vue-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts create mode 100644 vue-mark-rule/src/main.ts create mode 100644 vue-mark-rule/tsconfig.app.json create mode 100644 vue-mark-rule/tsconfig.json create mode 100644 vue-mark-rule/tsconfig.node.json create mode 100644 vue-mark-rule/vite.config.ts create mode 100644 vue-minimal/.gitignore create mode 100644 vue-minimal/README.md create mode 100644 vue-minimal/index.html create mode 100644 vue-minimal/package.json create mode 100644 vue-minimal/src/App.vue create mode 100644 vue-minimal/src/app.css create mode 100644 vue-minimal/src/components/editor/examples/minimal/editor.vue create mode 100644 vue-minimal/src/components/editor/examples/minimal/index.ts create mode 100644 vue-minimal/src/main.ts create mode 100644 vue-minimal/tsconfig.app.json create mode 100644 vue-minimal/tsconfig.json create mode 100644 vue-minimal/tsconfig.node.json create mode 100644 vue-minimal/vite.config.ts create mode 100644 vue-placeholder/.gitignore create mode 100644 vue-placeholder/README.md create mode 100644 vue-placeholder/index.html create mode 100644 vue-placeholder/package.json create mode 100644 vue-placeholder/src/App.vue create mode 100644 vue-placeholder/src/app.css create mode 100644 vue-placeholder/src/components/editor/examples/placeholder/editor.vue create mode 100644 vue-placeholder/src/components/editor/examples/placeholder/extension.ts create mode 100644 vue-placeholder/src/components/editor/examples/placeholder/index.ts create mode 100644 vue-placeholder/src/main.ts create mode 100644 vue-placeholder/tsconfig.app.json create mode 100644 vue-placeholder/tsconfig.json create mode 100644 vue-placeholder/tsconfig.node.json create mode 100644 vue-placeholder/vite.config.ts create mode 100644 vue-readonly/.gitignore create mode 100644 vue-readonly/README.md create mode 100644 vue-readonly/index.html create mode 100644 vue-readonly/package.json create mode 100644 vue-readonly/src/App.vue create mode 100644 vue-readonly/src/app.css create mode 100644 vue-readonly/src/components/editor/examples/readonly/editor.vue create mode 100644 vue-readonly/src/components/editor/examples/readonly/extension.ts create mode 100644 vue-readonly/src/components/editor/examples/readonly/index.ts create mode 100644 vue-readonly/src/components/editor/examples/readonly/toolbar.vue create mode 100644 vue-readonly/src/components/editor/examples/readonly/use-readonly.ts create mode 100644 vue-readonly/src/components/editor/sample/sample-doc-readonly.ts create mode 100644 vue-readonly/src/components/editor/ui/button/button.vue create mode 100644 vue-readonly/src/components/editor/ui/button/index.ts create mode 100644 vue-readonly/src/main.ts create mode 100644 vue-readonly/tsconfig.app.json create mode 100644 vue-readonly/tsconfig.json create mode 100644 vue-readonly/tsconfig.node.json create mode 100644 vue-readonly/vite.config.ts create mode 100644 vue-rtl/.gitignore create mode 100644 vue-rtl/README.md create mode 100644 vue-rtl/index.html create mode 100644 vue-rtl/package.json create mode 100644 vue-rtl/src/App.vue create mode 100644 vue-rtl/src/app.css create mode 100644 vue-rtl/src/components/editor/examples/rtl/editor.vue create mode 100644 vue-rtl/src/components/editor/examples/rtl/index.ts create mode 100644 vue-rtl/src/components/editor/sample/sample-doc-rtl.ts create mode 100644 vue-rtl/src/components/editor/sample/sample-uploader.ts create mode 100644 vue-rtl/src/components/editor/ui/block-handle/block-handle.vue create mode 100644 vue-rtl/src/components/editor/ui/block-handle/index.ts create mode 100644 vue-rtl/src/components/editor/ui/button/button.vue create mode 100644 vue-rtl/src/components/editor/ui/button/index.ts create mode 100644 vue-rtl/src/components/editor/ui/drop-indicator/drop-indicator.vue create mode 100644 vue-rtl/src/components/editor/ui/drop-indicator/index.ts create mode 100644 vue-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-rtl/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-rtl/src/components/editor/ui/inline-menu/index.ts create mode 100644 vue-rtl/src/components/editor/ui/inline-menu/inline-menu.vue create mode 100644 vue-rtl/src/components/editor/ui/slash-menu/index.ts create mode 100644 vue-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.vue create mode 100644 vue-rtl/src/components/editor/ui/slash-menu/slash-menu-item.vue create mode 100644 vue-rtl/src/components/editor/ui/slash-menu/slash-menu.vue create mode 100644 vue-rtl/src/components/editor/ui/table-handle/index.ts create mode 100644 vue-rtl/src/components/editor/ui/table-handle/table-handle.vue create mode 100644 vue-rtl/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-rtl/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-rtl/src/main.ts create mode 100644 vue-rtl/tsconfig.app.json create mode 100644 vue-rtl/tsconfig.json create mode 100644 vue-rtl/tsconfig.node.json create mode 100644 vue-rtl/vite.config.ts create mode 100644 vue-save-html/.gitignore create mode 100644 vue-save-html/README.md create mode 100644 vue-save-html/index.html create mode 100644 vue-save-html/package.json create mode 100644 vue-save-html/src/App.vue create mode 100644 vue-save-html/src/app.css create mode 100644 vue-save-html/src/components/editor/examples/save-html/editor.vue create mode 100644 vue-save-html/src/components/editor/examples/save-html/index.ts create mode 100644 vue-save-html/src/main.ts create mode 100644 vue-save-html/tsconfig.app.json create mode 100644 vue-save-html/tsconfig.json create mode 100644 vue-save-html/tsconfig.node.json create mode 100644 vue-save-html/vite.config.ts create mode 100644 vue-save-json/.gitignore create mode 100644 vue-save-json/README.md create mode 100644 vue-save-json/index.html create mode 100644 vue-save-json/package.json create mode 100644 vue-save-json/src/App.vue create mode 100644 vue-save-json/src/app.css create mode 100644 vue-save-json/src/components/editor/examples/save-json/editor.vue create mode 100644 vue-save-json/src/components/editor/examples/save-json/index.ts create mode 100644 vue-save-json/src/main.ts create mode 100644 vue-save-json/tsconfig.app.json create mode 100644 vue-save-json/tsconfig.json create mode 100644 vue-save-json/tsconfig.node.json create mode 100644 vue-save-json/vite.config.ts create mode 100644 vue-save-markdown/.gitignore create mode 100644 vue-save-markdown/README.md create mode 100644 vue-save-markdown/index.html create mode 100644 vue-save-markdown/package.json create mode 100644 vue-save-markdown/src/App.vue create mode 100644 vue-save-markdown/src/app.css create mode 100644 vue-save-markdown/src/components/editor/examples/save-markdown/editor.vue create mode 100644 vue-save-markdown/src/components/editor/examples/save-markdown/index.ts create mode 100644 vue-save-markdown/src/components/editor/examples/save-markdown/markdown.ts create mode 100644 vue-save-markdown/src/main.ts create mode 100644 vue-save-markdown/tsconfig.app.json create mode 100644 vue-save-markdown/tsconfig.json create mode 100644 vue-save-markdown/tsconfig.node.json create mode 100644 vue-save-markdown/vite.config.ts create mode 100644 vue-search/.gitignore create mode 100644 vue-search/README.md create mode 100644 vue-search/index.html create mode 100644 vue-search/package.json create mode 100644 vue-search/src/App.vue create mode 100644 vue-search/src/app.css create mode 100644 vue-search/src/components/editor/examples/search/editor.vue create mode 100644 vue-search/src/components/editor/examples/search/extension.ts create mode 100644 vue-search/src/components/editor/examples/search/index.ts create mode 100644 vue-search/src/components/editor/sample/sample-doc-search.ts create mode 100644 vue-search/src/components/editor/ui/button/button.vue create mode 100644 vue-search/src/components/editor/ui/button/index.ts create mode 100644 vue-search/src/components/editor/ui/search/index.ts create mode 100644 vue-search/src/components/editor/ui/search/search.vue create mode 100644 vue-search/src/main.ts create mode 100644 vue-search/tsconfig.app.json create mode 100644 vue-search/tsconfig.json create mode 100644 vue-search/tsconfig.node.json create mode 100644 vue-search/vite.config.ts create mode 100644 vue-slash-menu/.gitignore create mode 100644 vue-slash-menu/README.md create mode 100644 vue-slash-menu/index.html create mode 100644 vue-slash-menu/package.json create mode 100644 vue-slash-menu/src/App.vue create mode 100644 vue-slash-menu/src/app.css create mode 100644 vue-slash-menu/src/components/editor/examples/slash-menu/editor.vue create mode 100644 vue-slash-menu/src/components/editor/examples/slash-menu/extension.ts create mode 100644 vue-slash-menu/src/components/editor/examples/slash-menu/index.ts create mode 100644 vue-slash-menu/src/components/editor/ui/slash-menu/index.ts create mode 100644 vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.vue create mode 100644 vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.vue create mode 100644 vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu.vue create mode 100644 vue-slash-menu/src/main.ts create mode 100644 vue-slash-menu/tsconfig.app.json create mode 100644 vue-slash-menu/tsconfig.json create mode 100644 vue-slash-menu/tsconfig.node.json create mode 100644 vue-slash-menu/vite.config.ts create mode 100644 vue-strike/.gitignore create mode 100644 vue-strike/README.md create mode 100644 vue-strike/index.html create mode 100644 vue-strike/package.json create mode 100644 vue-strike/src/App.vue create mode 100644 vue-strike/src/app.css create mode 100644 vue-strike/src/components/editor/examples/strike/editor.vue create mode 100644 vue-strike/src/components/editor/examples/strike/extension.ts create mode 100644 vue-strike/src/components/editor/examples/strike/index.ts create mode 100644 vue-strike/src/components/editor/examples/strike/toolbar.vue create mode 100644 vue-strike/src/components/editor/sample/sample-doc-strike.ts create mode 100644 vue-strike/src/components/editor/ui/button/button.vue create mode 100644 vue-strike/src/components/editor/ui/button/index.ts create mode 100644 vue-strike/src/main.ts create mode 100644 vue-strike/tsconfig.app.json create mode 100644 vue-strike/tsconfig.json create mode 100644 vue-strike/tsconfig.node.json create mode 100644 vue-strike/vite.config.ts create mode 100644 vue-sub-sup/.gitignore create mode 100644 vue-sub-sup/README.md create mode 100644 vue-sub-sup/index.html create mode 100644 vue-sub-sup/package.json create mode 100644 vue-sub-sup/src/App.vue create mode 100644 vue-sub-sup/src/app.css create mode 100644 vue-sub-sup/src/components/editor/examples/sub-sup/editor.vue create mode 100644 vue-sub-sup/src/components/editor/examples/sub-sup/extension.ts create mode 100644 vue-sub-sup/src/components/editor/examples/sub-sup/index.ts create mode 100644 vue-sub-sup/src/components/editor/examples/sub-sup/toolbar.vue create mode 100644 vue-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts create mode 100644 vue-sub-sup/src/components/editor/ui/button/button.vue create mode 100644 vue-sub-sup/src/components/editor/ui/button/index.ts create mode 100644 vue-sub-sup/src/main.ts create mode 100644 vue-sub-sup/tsconfig.app.json create mode 100644 vue-sub-sup/tsconfig.json create mode 100644 vue-sub-sup/tsconfig.node.json create mode 100644 vue-sub-sup/vite.config.ts create mode 100644 vue-table/.gitignore create mode 100644 vue-table/README.md create mode 100644 vue-table/index.html create mode 100644 vue-table/package.json create mode 100644 vue-table/src/App.vue create mode 100644 vue-table/src/app.css create mode 100644 vue-table/src/components/editor/examples/table/editor.vue create mode 100644 vue-table/src/components/editor/examples/table/extension.ts create mode 100644 vue-table/src/components/editor/examples/table/index.ts create mode 100644 vue-table/src/components/editor/sample/sample-doc-table.ts create mode 100644 vue-table/src/components/editor/ui/table-handle/index.ts create mode 100644 vue-table/src/components/editor/ui/table-handle/table-handle.vue create mode 100644 vue-table/src/main.ts create mode 100644 vue-table/tsconfig.app.json create mode 100644 vue-table/tsconfig.json create mode 100644 vue-table/tsconfig.node.json create mode 100644 vue-table/vite.config.ts create mode 100644 vue-text-align/.gitignore create mode 100644 vue-text-align/README.md create mode 100644 vue-text-align/index.html create mode 100644 vue-text-align/package.json create mode 100644 vue-text-align/src/App.vue create mode 100644 vue-text-align/src/app.css create mode 100644 vue-text-align/src/components/editor/examples/text-align/editor.vue create mode 100644 vue-text-align/src/components/editor/examples/text-align/extension.ts create mode 100644 vue-text-align/src/components/editor/examples/text-align/index.ts create mode 100644 vue-text-align/src/components/editor/examples/text-align/toolbar.vue create mode 100644 vue-text-align/src/components/editor/sample/sample-doc-text-align.ts create mode 100644 vue-text-align/src/components/editor/ui/button/button.vue create mode 100644 vue-text-align/src/components/editor/ui/button/index.ts create mode 100644 vue-text-align/src/main.ts create mode 100644 vue-text-align/tsconfig.app.json create mode 100644 vue-text-align/tsconfig.json create mode 100644 vue-text-align/tsconfig.node.json create mode 100644 vue-text-align/vite.config.ts create mode 100644 vue-text-color/.gitignore create mode 100644 vue-text-color/README.md create mode 100644 vue-text-color/index.html create mode 100644 vue-text-color/package.json create mode 100644 vue-text-color/src/App.vue create mode 100644 vue-text-color/src/app.css create mode 100644 vue-text-color/src/components/editor/examples/text-color/editor.vue create mode 100644 vue-text-color/src/components/editor/examples/text-color/extension.ts create mode 100644 vue-text-color/src/components/editor/examples/text-color/index.ts create mode 100644 vue-text-color/src/components/editor/examples/text-color/inline-menu.vue create mode 100644 vue-text-color/src/components/editor/sample/sample-doc-text-color.ts create mode 100644 vue-text-color/src/components/editor/ui/button/button.vue create mode 100644 vue-text-color/src/components/editor/ui/button/index.ts create mode 100644 vue-text-color/src/main.ts create mode 100644 vue-text-color/tsconfig.app.json create mode 100644 vue-text-color/tsconfig.json create mode 100644 vue-text-color/tsconfig.node.json create mode 100644 vue-text-color/vite.config.ts create mode 100644 vue-toolbar/.gitignore create mode 100644 vue-toolbar/README.md create mode 100644 vue-toolbar/index.html create mode 100644 vue-toolbar/package.json create mode 100644 vue-toolbar/src/App.vue create mode 100644 vue-toolbar/src/app.css create mode 100644 vue-toolbar/src/components/editor/examples/toolbar/editor.vue create mode 100644 vue-toolbar/src/components/editor/examples/toolbar/extension.ts create mode 100644 vue-toolbar/src/components/editor/examples/toolbar/index.ts create mode 100644 vue-toolbar/src/components/editor/sample/sample-uploader.ts create mode 100644 vue-toolbar/src/components/editor/ui/button/button.vue create mode 100644 vue-toolbar/src/components/editor/ui/button/index.ts create mode 100644 vue-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-toolbar/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-toolbar/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-toolbar/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-toolbar/src/main.ts create mode 100644 vue-toolbar/tsconfig.app.json create mode 100644 vue-toolbar/tsconfig.json create mode 100644 vue-toolbar/tsconfig.node.json create mode 100644 vue-toolbar/vite.config.ts create mode 100644 vue-tweet/.gitignore create mode 100644 vue-tweet/README.md create mode 100644 vue-tweet/index.html create mode 100644 vue-tweet/package.json create mode 100644 vue-tweet/src/App.vue create mode 100644 vue-tweet/src/app.css create mode 100644 vue-tweet/src/components/editor/examples/tweet/editor.vue create mode 100644 vue-tweet/src/components/editor/examples/tweet/extension.ts create mode 100644 vue-tweet/src/components/editor/examples/tweet/index.ts create mode 100644 vue-tweet/src/components/editor/examples/tweet/method-select.vue create mode 100644 vue-tweet/src/components/editor/examples/tweet/tweet-view.vue create mode 100644 vue-tweet/src/components/editor/sample/sample-doc-tweet.ts create mode 100644 vue-tweet/src/main.ts create mode 100644 vue-tweet/tsconfig.app.json create mode 100644 vue-tweet/tsconfig.json create mode 100644 vue-tweet/tsconfig.node.json create mode 100644 vue-tweet/vite.config.ts create mode 100644 vue-typography/.gitignore create mode 100644 vue-typography/README.md create mode 100644 vue-typography/index.html create mode 100644 vue-typography/package.json create mode 100644 vue-typography/src/App.vue create mode 100644 vue-typography/src/app.css create mode 100644 vue-typography/src/components/editor/examples/typography/editor.vue create mode 100644 vue-typography/src/components/editor/examples/typography/extension.ts create mode 100644 vue-typography/src/components/editor/examples/typography/index.ts create mode 100644 vue-typography/src/components/editor/sample/katex.ts create mode 100644 vue-typography/src/components/editor/sample/sample-doc-typography.ts create mode 100644 vue-typography/src/components/editor/ui/block-handle/block-handle.vue create mode 100644 vue-typography/src/components/editor/ui/block-handle/index.ts create mode 100644 vue-typography/src/components/editor/ui/drop-indicator/drop-indicator.vue create mode 100644 vue-typography/src/components/editor/ui/drop-indicator/index.ts create mode 100644 vue-typography/src/main.ts create mode 100644 vue-typography/tsconfig.app.json create mode 100644 vue-typography/tsconfig.json create mode 100644 vue-typography/tsconfig.node.json create mode 100644 vue-typography/vite.config.ts create mode 100644 vue-underline/.gitignore create mode 100644 vue-underline/README.md create mode 100644 vue-underline/index.html create mode 100644 vue-underline/package.json create mode 100644 vue-underline/src/App.vue create mode 100644 vue-underline/src/app.css create mode 100644 vue-underline/src/components/editor/examples/underline/editor.vue create mode 100644 vue-underline/src/components/editor/examples/underline/extension.ts create mode 100644 vue-underline/src/components/editor/examples/underline/index.ts create mode 100644 vue-underline/src/components/editor/sample/sample-doc-underline.ts create mode 100644 vue-underline/src/components/editor/ui/button/button.vue create mode 100644 vue-underline/src/components/editor/ui/button/index.ts create mode 100644 vue-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-underline/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-underline/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-underline/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-underline/src/main.ts create mode 100644 vue-underline/tsconfig.app.json create mode 100644 vue-underline/tsconfig.json create mode 100644 vue-underline/tsconfig.node.json create mode 100644 vue-underline/vite.config.ts create mode 100644 vue-unmount/.gitignore create mode 100644 vue-unmount/README.md create mode 100644 vue-unmount/index.html create mode 100644 vue-unmount/package.json create mode 100644 vue-unmount/src/App.vue create mode 100644 vue-unmount/src/app.css create mode 100644 vue-unmount/src/components/editor/examples/unmount/editor-component.vue create mode 100644 vue-unmount/src/components/editor/examples/unmount/editor.vue create mode 100644 vue-unmount/src/components/editor/examples/unmount/extension-component.vue create mode 100644 vue-unmount/src/components/editor/examples/unmount/index.ts create mode 100644 vue-unmount/src/components/editor/ui/button/button.vue create mode 100644 vue-unmount/src/components/editor/ui/button/index.ts create mode 100644 vue-unmount/src/components/editor/ui/inline-menu/index.ts create mode 100644 vue-unmount/src/components/editor/ui/inline-menu/inline-menu.vue create mode 100644 vue-unmount/src/main.ts create mode 100644 vue-unmount/tsconfig.app.json create mode 100644 vue-unmount/tsconfig.json create mode 100644 vue-unmount/tsconfig.node.json create mode 100644 vue-unmount/vite.config.ts create mode 100644 vue-user-menu-dynamic/.gitignore create mode 100644 vue-user-menu-dynamic/README.md create mode 100644 vue-user-menu-dynamic/index.html create mode 100644 vue-user-menu-dynamic/package.json create mode 100644 vue-user-menu-dynamic/src/App.vue create mode 100644 vue-user-menu-dynamic/src/app.css create mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.vue create mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts create mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts create mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts create mode 100644 vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.vue create mode 100644 vue-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts create mode 100644 vue-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts create mode 100644 vue-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts create mode 100644 vue-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.vue create mode 100644 vue-user-menu-dynamic/src/main.ts create mode 100644 vue-user-menu-dynamic/tsconfig.app.json create mode 100644 vue-user-menu-dynamic/tsconfig.json create mode 100644 vue-user-menu-dynamic/tsconfig.node.json create mode 100644 vue-user-menu-dynamic/vite.config.ts create mode 100644 vue-user-menu/.gitignore create mode 100644 vue-user-menu/README.md create mode 100644 vue-user-menu/index.html create mode 100644 vue-user-menu/package.json create mode 100644 vue-user-menu/src/App.vue create mode 100644 vue-user-menu/src/app.css create mode 100644 vue-user-menu/src/components/editor/examples/user-menu/editor.vue create mode 100644 vue-user-menu/src/components/editor/examples/user-menu/extension.ts create mode 100644 vue-user-menu/src/components/editor/examples/user-menu/index.ts create mode 100644 vue-user-menu/src/components/editor/sample/sample-tag-data.ts create mode 100644 vue-user-menu/src/components/editor/sample/sample-user-data.ts create mode 100644 vue-user-menu/src/components/editor/ui/tag-menu/index.ts create mode 100644 vue-user-menu/src/components/editor/ui/tag-menu/tag-menu.vue create mode 100644 vue-user-menu/src/components/editor/ui/user-menu/index.ts create mode 100644 vue-user-menu/src/components/editor/ui/user-menu/user-menu.vue create mode 100644 vue-user-menu/src/main.ts create mode 100644 vue-user-menu/tsconfig.app.json create mode 100644 vue-user-menu/tsconfig.json create mode 100644 vue-user-menu/tsconfig.node.json create mode 100644 vue-user-menu/vite.config.ts create mode 100644 vue-word-counter/.gitignore create mode 100644 vue-word-counter/README.md create mode 100644 vue-word-counter/index.html create mode 100644 vue-word-counter/package.json create mode 100644 vue-word-counter/src/App.vue create mode 100644 vue-word-counter/src/app.css create mode 100644 vue-word-counter/src/components/editor/examples/word-counter/editor.vue create mode 100644 vue-word-counter/src/components/editor/examples/word-counter/extension.ts create mode 100644 vue-word-counter/src/components/editor/examples/word-counter/index.ts create mode 100644 vue-word-counter/src/components/editor/sample/sample-doc-word-counter.ts create mode 100644 vue-word-counter/src/components/editor/ui/word-counter/index.ts create mode 100644 vue-word-counter/src/components/editor/ui/word-counter/word-counter.vue create mode 100644 vue-word-counter/src/main.ts create mode 100644 vue-word-counter/tsconfig.app.json create mode 100644 vue-word-counter/tsconfig.json create mode 100644 vue-word-counter/tsconfig.node.json create mode 100644 vue-word-counter/vite.config.ts create mode 100644 vue-yjs/.gitignore create mode 100644 vue-yjs/README.md create mode 100644 vue-yjs/index.html create mode 100644 vue-yjs/package.json create mode 100644 vue-yjs/src/App.vue create mode 100644 vue-yjs/src/app.css create mode 100644 vue-yjs/src/components/editor/examples/yjs/editor-component.vue create mode 100644 vue-yjs/src/components/editor/examples/yjs/editor.vue create mode 100644 vue-yjs/src/components/editor/examples/yjs/extension.ts create mode 100644 vue-yjs/src/components/editor/examples/yjs/index.ts create mode 100644 vue-yjs/src/components/editor/ui/button/button.vue create mode 100644 vue-yjs/src/components/editor/ui/button/index.ts create mode 100644 vue-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.vue create mode 100644 vue-yjs/src/components/editor/ui/image-upload-popover/index.ts create mode 100644 vue-yjs/src/components/editor/ui/toolbar/index.ts create mode 100644 vue-yjs/src/components/editor/ui/toolbar/toolbar.vue create mode 100644 vue-yjs/src/main.ts create mode 100644 vue-yjs/tsconfig.app.json create mode 100644 vue-yjs/tsconfig.json create mode 100644 vue-yjs/tsconfig.node.json create mode 100644 vue-yjs/vite.config.ts diff --git a/lit-block-handle/.gitignore b/lit-block-handle/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/lit-block-handle/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/lit-block-handle/README.md b/lit-block-handle/README.md new file mode 100644 index 0000000000..05508d749e --- /dev/null +++ b/lit-block-handle/README.md @@ -0,0 +1,15 @@ +# lit-block-handle + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-block-handle) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-block-handle) + +Run the example locally with: + +```bash +npx degit prosekit/examples/lit-block-handle lit-block-handle +cd lit-block-handle +npm install +npm run dev +``` diff --git a/lit-block-handle/index.html b/lit-block-handle/index.html new file mode 100644 index 0000000000..9637b16269 --- /dev/null +++ b/lit-block-handle/index.html @@ -0,0 +1,13 @@ + + + + + + ProseKit + Lit + + + + + + + diff --git a/lit-block-handle/package.json b/lit-block-handle/package.json new file mode 100644 index 0000000000..10af979864 --- /dev/null +++ b/lit-block-handle/package.json @@ -0,0 +1,24 @@ +{ + "name": "example-lit-block-handle", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "@lit/context": "^1.1.6", + "lit": "^3.3.2", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/lit-block-handle/src/app.css b/lit-block-handle/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/lit-block-handle/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/lit-block-handle/src/app.ts b/lit-block-handle/src/app.ts new file mode 100644 index 0000000000..3cbf14f94d --- /dev/null +++ b/lit-block-handle/src/app.ts @@ -0,0 +1,18 @@ +import './app.css' +import './editor' + +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +@customElement('my-app') +export class MyApp extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-block-handle/src/components/editor/examples/block-handle/editor.ts b/lit-block-handle/src/components/editor/examples/block-handle/editor.ts new file mode 100644 index 0000000000..0e4a1d8857 --- /dev/null +++ b/lit-block-handle/src/components/editor/examples/block-handle/editor.ts @@ -0,0 +1,99 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { ContextProvider } from '@lit/context' +import { + html, + LitElement, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import { createRef, ref, type Ref } from 'lit/directives/ref.js' +import type { Editor, NodeJSON } from 'prosekit/core' +import { createEditor } from 'prosekit/core' + +import { sampleContent } from '../../sample/sample-doc-block-handle' +import { registerLitEditorBlockHandle } from '../../ui/block-handle' +import { registerLitEditorDropIndicator } from '../../ui/drop-indicator' +import { editorContext } from '../../ui/editor-context' + +import { defineExtension } from './extension' + +export class LitEditor extends LitElement { + static override properties = { + initialContent: { + attribute: false, + } satisfies PropertyDeclaration, + } + + initialContent?: NodeJSON + + private editor?: Editor + private ref: Ref + + constructor() { + super() + this.ref = createRef() + } + + override createRenderRoot() { + return this + } + + override disconnectedCallback() { + this.editor?.unmount() + super.disconnectedCallback() + } + + override willUpdate() { + if (this.editor) { + return + } + + const extension = defineExtension() + this.editor = createEditor({ + extension, + defaultContent: this.initialContent ?? sampleContent, + }) + new ContextProvider(this, { + context: editorContext, + initialValue: this.editor, + }) + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.editor?.mount(this.ref.value) + } + + override render() { + return html` +
+
+
+ + +
+
+ ` + } +} + +export function registerLitEditor() { + registerLitEditorBlockHandle() + registerLitEditorDropIndicator() + + if (customElements.get('lit-editor-example-block-handle')) return + customElements.define('lit-editor-example-block-handle', LitEditor) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-example-block-handle': LitEditor + } +} diff --git a/lit-block-handle/src/components/editor/examples/block-handle/extension.ts b/lit-block-handle/src/components/editor/examples/block-handle/extension.ts new file mode 100644 index 0000000000..b5686b8c04 --- /dev/null +++ b/lit-block-handle/src/components/editor/examples/block-handle/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union(defineBasicExtension(), defineCodeBlockView()) +} + +export type EditorExtension = ReturnType diff --git a/lit-block-handle/src/components/editor/examples/block-handle/index.ts b/lit-block-handle/src/components/editor/examples/block-handle/index.ts new file mode 100644 index 0000000000..9eeecbbc50 --- /dev/null +++ b/lit-block-handle/src/components/editor/examples/block-handle/index.ts @@ -0,0 +1 @@ +export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/lit-block-handle/src/components/editor/sample/sample-doc-block-handle.ts new file mode 100644 index 0000000000..3c6ccdc203 --- /dev/null +++ b/lit-block-handle/src/components/editor/sample/sample-doc-block-handle.ts @@ -0,0 +1,323 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Drag and Drop Demo', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Getting Started', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This paragraph can be moved above or below other blocks.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Different Block Types', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'You can drag paragraphs, headings, lists, code blocks, and more.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Lists Work Too', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This entire list can be dragged', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Individual list items stay together', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try moving this list around', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Ordered lists also support dragging', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The numbering updates automatically', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag this list to see it in action', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Even code blocks can be moved:', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: 'javascript', + }, + content: [ + { + type: 'text', + text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Nested Content', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This blockquote can be moved as a single unit.', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested blockquotes move together with their parent.', + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Try It Yourself', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Practice by moving this paragraph to the top of the document.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Or drag this one to between the headings above.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The drag handles make it easy to reorganize your content exactly how you want it.', + }, + ], + }, + ], +} diff --git a/lit-block-handle/src/components/editor/ui/block-handle/block-handle.ts b/lit-block-handle/src/components/editor/ui/block-handle/block-handle.ts new file mode 100644 index 0000000000..7cc4822558 --- /dev/null +++ b/lit-block-handle/src/components/editor/ui/block-handle/block-handle.ts @@ -0,0 +1,77 @@ +import { ContextConsumer } from '@lit/context' +import { html, LitElement } from 'lit' +import { + registerBlockHandleAddElement, + registerBlockHandleDraggableElement, + registerBlockHandlePopupElement, + registerBlockHandlePositionerElement, + registerBlockHandleRootElement, +} from 'prosekit/lit/block-handle' + +import { editorContext } from '../editor-context' + +class LitBlockHandle extends LitElement { + declare dir: 'ltr' | 'rtl' | 'auto' + + private _editorConsumer = new ContextConsumer(this, { + context: editorContext, + subscribe: true, + }) + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + } + + override createRenderRoot() { + return this + } + + override render() { + const placement = this.dir === 'rtl' ? 'right' : 'left' + const editor = this._editorConsumer.value ?? null + + return html` + + + + +
+
+ +
+
+
+
+
+ ` + } +} + +export function registerLitEditorBlockHandle() { + registerBlockHandleAddElement() + registerBlockHandleDraggableElement() + registerBlockHandlePopupElement() + registerBlockHandlePositionerElement() + registerBlockHandleRootElement() + + if (customElements.get('lit-editor-block-handle')) return + customElements.define('lit-editor-block-handle', LitBlockHandle) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-block-handle': LitBlockHandle + } +} diff --git a/lit-block-handle/src/components/editor/ui/block-handle/index.ts b/lit-block-handle/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..40c59d8d74 --- /dev/null +++ b/lit-block-handle/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { registerLitEditorBlockHandle } from './block-handle' diff --git a/lit-block-handle/src/components/editor/ui/code-block-view/code-block-view.ts b/lit-block-handle/src/components/editor/ui/code-block-view/code-block-view.ts new file mode 100644 index 0000000000..ce30a8fd93 --- /dev/null +++ b/lit-block-handle/src/components/editor/ui/code-block-view/code-block-view.ts @@ -0,0 +1,106 @@ +import type { Extension } from 'prosekit/core' +import { defineNodeView } from 'prosekit/core' +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { ProseMirrorNode } from 'prosekit/pm/model' +import type { EditorView } from 'prosekit/pm/view' + +class CodeBlockNodeView { + dom: HTMLElement + contentDOM: HTMLElement + private node: ProseMirrorNode + private view: EditorView + private getPos: () => number | undefined + private select: HTMLSelectElement + private pre: HTMLPreElement + + constructor( + node: ProseMirrorNode, + view: EditorView, + getPos: () => number | undefined, + ) { + this.node = node + this.view = view + this.getPos = getPos + + const root = document.createElement('div') + root.setAttribute('data-node-view-root', 'true') + + const wrapper = document.createElement('div') + wrapper.className = + 'relative mx-2 top-3 h-0 select-none overflow-visible text-xs' + wrapper.setAttribute('contenteditable', 'false') + + this.select = document.createElement('select') + this.select.setAttribute('aria-label', 'Code block language') + this.select.className = + 'outline-unset focus:outline-unset relative box-border w-auto cursor-pointer select-none appearance-none rounded-sm border-none bg-transparent px-2 py-1 text-xs transition text-(--prosemirror-highlight) opacity-0 hover:opacity-80 [div[data-node-view-root]:hover_&]:opacity-50 hover:[div[data-node-view-root]:hover_&]:opacity-80' + + const plain = document.createElement('option') + plain.value = '' + plain.textContent = 'Plain Text' + this.select.appendChild(plain) + + for (const info of shikiBundledLanguagesInfo) { + const option = document.createElement('option') + option.value = info.id + option.textContent = info.name + this.select.appendChild(option) + } + + this.select.addEventListener('change', this.handleChange) + wrapper.appendChild(this.select) + + this.pre = document.createElement('pre') + this.contentDOM = document.createElement('code') + this.contentDOM.setAttribute('data-node-view-content', 'true') + this.contentDOM.style.whiteSpace = 'inherit' + this.pre.appendChild(this.contentDOM) + + root.appendChild(wrapper) + root.appendChild(this.pre) + + this.dom = root + this.syncAttrs() + } + + private handleChange = (event: Event) => { + const language = (event.target as HTMLSelectElement).value + const pos = this.getPos() + if (typeof pos !== 'number') return + const attrs: CodeBlockAttrs = { + ...(this.node.attrs as CodeBlockAttrs), + language, + } + this.view.dispatch(this.view.state.tr.setNodeMarkup(pos, undefined, attrs)) + } + + private syncAttrs() { + const language = (this.node.attrs as CodeBlockAttrs).language || '' + this.select.value = language + if (language) { + this.pre.setAttribute('data-language', language) + } else { + this.pre.removeAttribute('data-language') + } + } + + update(node: ProseMirrorNode) { + if (node.type !== this.node.type) return false + this.node = node + this.syncAttrs() + return true + } + + destroy() { + this.select.removeEventListener('change', this.handleChange) + } +} + +export function defineCodeBlockView(): Extension { + return defineNodeView({ + name: 'codeBlock', + constructor: (node, view, getPos) => + new CodeBlockNodeView(node, view, getPos), + }) +} diff --git a/lit-block-handle/src/components/editor/ui/code-block-view/index.ts b/lit-block-handle/src/components/editor/ui/code-block-view/index.ts new file mode 100644 index 0000000000..a96ff094eb --- /dev/null +++ b/lit-block-handle/src/components/editor/ui/code-block-view/index.ts @@ -0,0 +1 @@ +export { defineCodeBlockView } from './code-block-view' diff --git a/lit-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.ts b/lit-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.ts new file mode 100644 index 0000000000..b18f3c6a20 --- /dev/null +++ b/lit-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.ts @@ -0,0 +1,43 @@ +import { ContextConsumer } from '@lit/context' +import { html, LitElement } from 'lit' +import { registerDropIndicatorElement } from 'prosekit/lit/drop-indicator' + +import { editorContext } from '../editor-context' + +class LitDropIndicator extends LitElement { + private _editorConsumer = new ContextConsumer(this, { + context: editorContext, + subscribe: true, + }) + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + } + + override createRenderRoot() { + return this + } + + override render() { + return html` + + ` + } +} + +export function registerLitEditorDropIndicator() { + registerDropIndicatorElement() + + if (customElements.get('lit-editor-drop-indicator')) return + customElements.define('lit-editor-drop-indicator', LitDropIndicator) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-drop-indicator': LitDropIndicator + } +} diff --git a/lit-block-handle/src/components/editor/ui/drop-indicator/index.ts b/lit-block-handle/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..f90b74e908 --- /dev/null +++ b/lit-block-handle/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { registerLitEditorDropIndicator } from './drop-indicator' diff --git a/lit-block-handle/src/components/editor/ui/editor-context.ts b/lit-block-handle/src/components/editor/ui/editor-context.ts new file mode 100644 index 0000000000..7af6d3a865 --- /dev/null +++ b/lit-block-handle/src/components/editor/ui/editor-context.ts @@ -0,0 +1,6 @@ +import { createContext } from '@lit/context' +import type { Editor } from 'prosekit/core' + +export const editorContext = createContext( + 'prosekit-editor', +) diff --git a/lit-block-handle/src/editor.ts b/lit-block-handle/src/editor.ts new file mode 100644 index 0000000000..2c676875fb --- /dev/null +++ b/lit-block-handle/src/editor.ts @@ -0,0 +1,18 @@ +import { registerLitEditor } from './components/editor/examples/block-handle' +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +registerLitEditor() + +@customElement('my-editor') +export class MyEditor extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-block-handle/tsconfig.json b/lit-block-handle/tsconfig.json new file mode 100644 index 0000000000..f3ad657d5f --- /dev/null +++ b/lit-block-handle/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es2023", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "esnext", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/lit-block-handle/vite.config.ts b/lit-block-handle/vite.config.ts new file mode 100644 index 0000000000..fb0cdf00b5 --- /dev/null +++ b/lit-block-handle/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [tailwindcss()], +}) diff --git a/lit-code-block/.gitignore b/lit-code-block/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/lit-code-block/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/lit-code-block/README.md b/lit-code-block/README.md new file mode 100644 index 0000000000..33cd50e77b --- /dev/null +++ b/lit-code-block/README.md @@ -0,0 +1,15 @@ +# lit-code-block + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-code-block) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-code-block) + +Run the example locally with: + +```bash +npx degit prosekit/examples/lit-code-block lit-code-block +cd lit-code-block +npm install +npm run dev +``` diff --git a/lit-code-block/index.html b/lit-code-block/index.html new file mode 100644 index 0000000000..9637b16269 --- /dev/null +++ b/lit-code-block/index.html @@ -0,0 +1,13 @@ + + + + + + ProseKit + Lit + + + + + + + diff --git a/lit-code-block/package.json b/lit-code-block/package.json new file mode 100644 index 0000000000..6e560b72f8 --- /dev/null +++ b/lit-code-block/package.json @@ -0,0 +1,24 @@ +{ + "name": "example-lit-code-block", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "@lit/context": "^1.1.6", + "lit": "^3.3.2", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/lit-code-block/src/app.css b/lit-code-block/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/lit-code-block/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/lit-code-block/src/app.ts b/lit-code-block/src/app.ts new file mode 100644 index 0000000000..3cbf14f94d --- /dev/null +++ b/lit-code-block/src/app.ts @@ -0,0 +1,18 @@ +import './app.css' +import './editor' + +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +@customElement('my-app') +export class MyApp extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-code-block/src/components/editor/examples/code-block/editor.ts b/lit-code-block/src/components/editor/examples/code-block/editor.ts new file mode 100644 index 0000000000..b7b768ffbe --- /dev/null +++ b/lit-code-block/src/components/editor/examples/code-block/editor.ts @@ -0,0 +1,87 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { ContextProvider } from '@lit/context' +import { + html, + LitElement, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import { createRef, ref, type Ref } from 'lit/directives/ref.js' +import type { Editor } from 'prosekit/core' +import { createEditor } from 'prosekit/core' + +import { sampleContent } from '../../sample/sample-doc-code-block' +import { sampleUploader } from '../../sample/sample-uploader' +import { editorContext } from '../../ui/editor-context' +import { registerLitEditorToolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export class LitEditor extends LitElement { + static override properties = { + editor: { + state: true, + attribute: false, + } satisfies PropertyDeclaration, + } + + private editor: Editor + private ref: Ref + + constructor() { + super() + + const extension = defineExtension() + this.editor = createEditor({ extension, defaultContent: sampleContent }) + this.ref = createRef() + new ContextProvider(this, { + context: editorContext, + initialValue: this.editor, + }) + } + + override createRenderRoot() { + return this + } + + override disconnectedCallback() { + this.editor.unmount() + super.disconnectedCallback() + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.editor.mount(this.ref.value) + } + + override render() { + return html` +
+ +
+
+
+
+ ` + } +} + +export function registerLitEditor() { + registerLitEditorToolbar() + + if (customElements.get('lit-editor-example-code-block')) return + customElements.define('lit-editor-example-code-block', LitEditor) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-example-code-block': LitEditor + } +} diff --git a/lit-code-block/src/components/editor/examples/code-block/extension.ts b/lit-code-block/src/components/editor/examples/code-block/extension.ts new file mode 100644 index 0000000000..099cacf03b --- /dev/null +++ b/lit-code-block/src/components/editor/examples/code-block/extension.ts @@ -0,0 +1,24 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { + defineCodeBlock, + defineCodeBlockShiki, +} from 'prosekit/extensions/code-block' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCodeBlock(), + defineCodeBlockShiki(), + defineCodeBlockView(), + ) +} + +export type EditorExtension = ReturnType diff --git a/lit-code-block/src/components/editor/examples/code-block/index.ts b/lit-code-block/src/components/editor/examples/code-block/index.ts new file mode 100644 index 0000000000..9eeecbbc50 --- /dev/null +++ b/lit-code-block/src/components/editor/examples/code-block/index.ts @@ -0,0 +1 @@ +export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-code-block/src/components/editor/sample/sample-doc-code-block.ts b/lit-code-block/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/lit-code-block/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/lit-code-block/src/components/editor/sample/sample-uploader.ts b/lit-code-block/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/lit-code-block/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/lit-code-block/src/components/editor/ui/button/button.ts b/lit-code-block/src/components/editor/ui/button/button.ts new file mode 100644 index 0000000000..aef47e4e1f --- /dev/null +++ b/lit-code-block/src/components/editor/ui/button/button.ts @@ -0,0 +1,92 @@ +import { html, LitElement, nothing, type PropertyDeclaration } from 'lit' +import { + registerTooltipPopupElement, + registerTooltipPositionerElement, + registerTooltipRootElement, + registerTooltipTriggerElement, +} from 'prosekit/lit/tooltip' + +class LitButton extends LitElement { + static override properties = { + pressed: { type: Boolean }, + disabled: { type: Boolean }, + tooltip: { type: String }, + icon: { type: String }, + } satisfies Record + + pressed = false + disabled = false + tooltip = '' + icon = '' + + override createRenderRoot() { + return this + } + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + } + + private handleMouseDown = (event: MouseEvent) => { + // Prevent the editor from being blurred when the button is clicked + event.preventDefault() + } + + override render() { + const tooltip = this.tooltip + + return html` + + + + + ${tooltip + ? html` + + + ${tooltip} + + + ` + : nothing} + + ` + } +} + +export function registerLitEditorButton() { + registerTooltipPopupElement() + registerTooltipPositionerElement() + registerTooltipRootElement() + registerTooltipTriggerElement() + + if (customElements.get('lit-editor-button')) return + customElements.define('lit-editor-button', LitButton) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-button': LitButton + } +} diff --git a/lit-code-block/src/components/editor/ui/button/index.ts b/lit-code-block/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..02efbeadd2 --- /dev/null +++ b/lit-code-block/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { registerLitEditorButton } from './button' diff --git a/lit-code-block/src/components/editor/ui/code-block-view/code-block-view.ts b/lit-code-block/src/components/editor/ui/code-block-view/code-block-view.ts new file mode 100644 index 0000000000..ce30a8fd93 --- /dev/null +++ b/lit-code-block/src/components/editor/ui/code-block-view/code-block-view.ts @@ -0,0 +1,106 @@ +import type { Extension } from 'prosekit/core' +import { defineNodeView } from 'prosekit/core' +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { ProseMirrorNode } from 'prosekit/pm/model' +import type { EditorView } from 'prosekit/pm/view' + +class CodeBlockNodeView { + dom: HTMLElement + contentDOM: HTMLElement + private node: ProseMirrorNode + private view: EditorView + private getPos: () => number | undefined + private select: HTMLSelectElement + private pre: HTMLPreElement + + constructor( + node: ProseMirrorNode, + view: EditorView, + getPos: () => number | undefined, + ) { + this.node = node + this.view = view + this.getPos = getPos + + const root = document.createElement('div') + root.setAttribute('data-node-view-root', 'true') + + const wrapper = document.createElement('div') + wrapper.className = + 'relative mx-2 top-3 h-0 select-none overflow-visible text-xs' + wrapper.setAttribute('contenteditable', 'false') + + this.select = document.createElement('select') + this.select.setAttribute('aria-label', 'Code block language') + this.select.className = + 'outline-unset focus:outline-unset relative box-border w-auto cursor-pointer select-none appearance-none rounded-sm border-none bg-transparent px-2 py-1 text-xs transition text-(--prosemirror-highlight) opacity-0 hover:opacity-80 [div[data-node-view-root]:hover_&]:opacity-50 hover:[div[data-node-view-root]:hover_&]:opacity-80' + + const plain = document.createElement('option') + plain.value = '' + plain.textContent = 'Plain Text' + this.select.appendChild(plain) + + for (const info of shikiBundledLanguagesInfo) { + const option = document.createElement('option') + option.value = info.id + option.textContent = info.name + this.select.appendChild(option) + } + + this.select.addEventListener('change', this.handleChange) + wrapper.appendChild(this.select) + + this.pre = document.createElement('pre') + this.contentDOM = document.createElement('code') + this.contentDOM.setAttribute('data-node-view-content', 'true') + this.contentDOM.style.whiteSpace = 'inherit' + this.pre.appendChild(this.contentDOM) + + root.appendChild(wrapper) + root.appendChild(this.pre) + + this.dom = root + this.syncAttrs() + } + + private handleChange = (event: Event) => { + const language = (event.target as HTMLSelectElement).value + const pos = this.getPos() + if (typeof pos !== 'number') return + const attrs: CodeBlockAttrs = { + ...(this.node.attrs as CodeBlockAttrs), + language, + } + this.view.dispatch(this.view.state.tr.setNodeMarkup(pos, undefined, attrs)) + } + + private syncAttrs() { + const language = (this.node.attrs as CodeBlockAttrs).language || '' + this.select.value = language + if (language) { + this.pre.setAttribute('data-language', language) + } else { + this.pre.removeAttribute('data-language') + } + } + + update(node: ProseMirrorNode) { + if (node.type !== this.node.type) return false + this.node = node + this.syncAttrs() + return true + } + + destroy() { + this.select.removeEventListener('change', this.handleChange) + } +} + +export function defineCodeBlockView(): Extension { + return defineNodeView({ + name: 'codeBlock', + constructor: (node, view, getPos) => + new CodeBlockNodeView(node, view, getPos), + }) +} diff --git a/lit-code-block/src/components/editor/ui/code-block-view/index.ts b/lit-code-block/src/components/editor/ui/code-block-view/index.ts new file mode 100644 index 0000000000..a96ff094eb --- /dev/null +++ b/lit-code-block/src/components/editor/ui/code-block-view/index.ts @@ -0,0 +1 @@ +export { defineCodeBlockView } from './code-block-view' diff --git a/lit-code-block/src/components/editor/ui/editor-context.ts b/lit-code-block/src/components/editor/ui/editor-context.ts new file mode 100644 index 0000000000..7af6d3a865 --- /dev/null +++ b/lit-code-block/src/components/editor/ui/editor-context.ts @@ -0,0 +1,6 @@ +import { createContext } from '@lit/context' +import type { Editor } from 'prosekit/core' + +export const editorContext = createContext( + 'prosekit-editor', +) diff --git a/lit-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.ts b/lit-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.ts new file mode 100644 index 0000000000..3a129e53de --- /dev/null +++ b/lit-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.ts @@ -0,0 +1,200 @@ +import { html, LitElement, nothing, type PropertyDeclaration } from 'lit' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { + registerPopoverPopupElement, + registerPopoverPositionerElement, + registerPopoverRootElement, + registerPopoverTriggerElement, + type OpenChangeEvent, +} from 'prosekit/lit/popover' + +import { registerLitEditorButton } from '../button' + +let imageUploadId = 0 + +class LitImageUploadPopover extends LitElement { + static override properties = { + editor: { attribute: false } satisfies PropertyDeclaration, + uploader: { attribute: false } satisfies PropertyDeclaration< + Uploader + >, + tooltip: { type: String }, + disabled: { type: Boolean }, + icon: { type: String }, + } + + editor?: Editor + uploader?: Uploader + tooltip = '' + disabled = false + icon = '' + + private open = false + private url = '' + private file: File | null = null + private ariaId = `lit-image-upload-${imageUploadId++}` + + override createRenderRoot() { + return this + } + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + } + + private handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + this.deferResetState() + } + + this.open = event.detail + this.requestUpdate() + } + + private handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + this.file = selectedFile + this.url = '' + } else { + this.file = null + } + + this.requestUpdate() + } + + private handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + this.url = inputUrl + this.file = null + } else { + this.url = '' + } + + this.requestUpdate() + } + + private deferResetState() { + setTimeout(() => { + this.url = '' + this.file = null + this.requestUpdate() + }, 300) + } + + private handleSubmit = () => { + const editor = this.editor + if (!editor) return + + if (this.url) { + editor.commands.insertImage({ src: this.url }) + } else if (this.file && this.uploader) { + editor.commands.uploadImage({ file: this.file, uploader: this.uploader }) + } + + this.open = false + this.deferResetState() + this.requestUpdate() + } + + override render() { + return html` + + + + + + + + ${!this.file + ? html` + + + ` + : nothing} + ${!this.url + ? html` + + + ` + : nothing} + ${this.url + ? html` + + ` + : nothing} + ${this.file + ? html` + + ` + : nothing} + + + + ` + } +} + +export function registerLitEditorImageUploadPopover() { + registerLitEditorButton() + registerPopoverPopupElement() + registerPopoverPositionerElement() + registerPopoverRootElement() + registerPopoverTriggerElement() + + if (customElements.get('lit-editor-image-upload-popover')) return + customElements.define( + 'lit-editor-image-upload-popover', + LitImageUploadPopover, + ) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-image-upload-popover': LitImageUploadPopover + } +} diff --git a/lit-code-block/src/components/editor/ui/image-upload-popover/index.ts b/lit-code-block/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ff00f20c86 --- /dev/null +++ b/lit-code-block/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { registerLitEditorImageUploadPopover } from './image-upload-popover' diff --git a/lit-code-block/src/components/editor/ui/toolbar/index.ts b/lit-code-block/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..6d6df28ea4 --- /dev/null +++ b/lit-code-block/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { registerLitEditorToolbar } from './toolbar' diff --git a/lit-code-block/src/components/editor/ui/toolbar/toolbar.ts b/lit-code-block/src/components/editor/ui/toolbar/toolbar.ts new file mode 100644 index 0000000000..ee46ea40a1 --- /dev/null +++ b/lit-code-block/src/components/editor/ui/toolbar/toolbar.ts @@ -0,0 +1,467 @@ +import { ContextConsumer } from '@lit/context' +import { + html, + LitElement, + nothing, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import type { BasicExtension } from 'prosekit/basic' +import { defineUpdateHandler, type Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' + +import { registerLitEditorButton } from '../button' +import { editorContext } from '../editor-context' +import { registerLitEditorImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +class LitToolbar extends LitElement { + static override properties = { + uploader: { attribute: false } satisfies PropertyDeclaration< + Uploader + >, + } + + uploader?: Uploader + + private editorConsumer = new ContextConsumer(this, { + context: editorContext, + subscribe: true, + }) + + private removeUpdateExtension?: VoidFunction + + override createRenderRoot() { + return this + } + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + this.attachEditorListener() + } + + override disconnectedCallback() { + this.detachEditorListener() + super.disconnectedCallback() + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.attachEditorListener() + } + + private attachEditorListener() { + this.detachEditorListener() + + const editor = this.editorConsumer.value + if (!editor) return + + this.removeUpdateExtension = editor.use( + defineUpdateHandler(() => this.requestUpdate()), + ) + } + + private detachEditorListener() { + this.removeUpdateExtension?.() + this.removeUpdateExtension = undefined + } + + override render() { + const editor = this.editorConsumer.value as + | Editor + | undefined + if (!editor) { + return nothing + } + + const items = getToolbarItems(editor) + + return html` +
+ ${items.undo + ? html` + + ` + : nothing} + ${items.redo + ? html` + + ` + : nothing} + ${items.bold + ? html` + + ` + : nothing} + ${items.italic + ? html` + + ` + : nothing} + ${items.underline + ? html` + + ` + : nothing} + ${items.strike + ? html` + + ` + : nothing} + ${items.code + ? html` + + ` + : nothing} + ${items.codeBlock + ? html` + + ` + : nothing} + ${items.heading1 + ? html` + + ` + : nothing} + ${items.heading2 + ? html` + + ` + : nothing} + ${items.heading3 + ? html` + + ` + : nothing} + ${items.horizontalRule + ? html` + + ` + : nothing} + ${items.blockquote + ? html` + + ` + : nothing} + ${items.bulletList + ? html` + + ` + : nothing} + ${items.orderedList + ? html` + + ` + : nothing} + ${items.taskList + ? html` + + ` + : nothing} + ${items.toggleList + ? html` + + ` + : nothing} + ${items.indentList + ? html` + + ` + : nothing} + ${items.dedentList + ? html` + + ` + : nothing} + ${this.uploader && items.insertImage + ? html` + + ` + : nothing} +
+ ` + } +} + +export function registerLitEditorToolbar() { + registerLitEditorButton() + registerLitEditorImageUploadPopover() + + if (customElements.get('lit-editor-toolbar')) return + customElements.define('lit-editor-toolbar', LitToolbar) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-toolbar': LitToolbar + } +} diff --git a/lit-code-block/src/editor.ts b/lit-code-block/src/editor.ts new file mode 100644 index 0000000000..95412c3a91 --- /dev/null +++ b/lit-code-block/src/editor.ts @@ -0,0 +1,18 @@ +import { registerLitEditor } from './components/editor/examples/code-block' +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +registerLitEditor() + +@customElement('my-editor') +export class MyEditor extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-code-block/tsconfig.json b/lit-code-block/tsconfig.json new file mode 100644 index 0000000000..f3ad657d5f --- /dev/null +++ b/lit-code-block/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es2023", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "esnext", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/lit-code-block/vite.config.ts b/lit-code-block/vite.config.ts new file mode 100644 index 0000000000..fb0cdf00b5 --- /dev/null +++ b/lit-code-block/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [tailwindcss()], +}) diff --git a/lit-minimal/.gitignore b/lit-minimal/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/lit-minimal/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/lit-minimal/README.md b/lit-minimal/README.md new file mode 100644 index 0000000000..954cc8c15d --- /dev/null +++ b/lit-minimal/README.md @@ -0,0 +1,15 @@ +# lit-minimal + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-minimal) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-minimal) + +Run the example locally with: + +```bash +npx degit prosekit/examples/lit-minimal lit-minimal +cd lit-minimal +npm install +npm run dev +``` diff --git a/lit-minimal/index.html b/lit-minimal/index.html new file mode 100644 index 0000000000..9637b16269 --- /dev/null +++ b/lit-minimal/index.html @@ -0,0 +1,13 @@ + + + + + + ProseKit + Lit + + + + + + + diff --git a/lit-minimal/package.json b/lit-minimal/package.json new file mode 100644 index 0000000000..2b8a933675 --- /dev/null +++ b/lit-minimal/package.json @@ -0,0 +1,23 @@ +{ + "name": "example-lit-minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "lit": "^3.3.2", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/lit-minimal/src/app.css b/lit-minimal/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/lit-minimal/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/lit-minimal/src/app.ts b/lit-minimal/src/app.ts new file mode 100644 index 0000000000..3cbf14f94d --- /dev/null +++ b/lit-minimal/src/app.ts @@ -0,0 +1,18 @@ +import './app.css' +import './editor' + +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +@customElement('my-app') +export class MyApp extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-minimal/src/components/editor/examples/minimal/editor.ts b/lit-minimal/src/components/editor/examples/minimal/editor.ts new file mode 100644 index 0000000000..5603677c48 --- /dev/null +++ b/lit-minimal/src/components/editor/examples/minimal/editor.ts @@ -0,0 +1,64 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { + html, + LitElement, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import { createRef, ref, type Ref } from 'lit/directives/ref.js' +import { defineBasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import { createEditor } from 'prosekit/core' + +export class LitEditor extends LitElement { + static override properties = { + editor: { + state: true, + attribute: false, + } satisfies PropertyDeclaration, + } + + private editor: Editor + private ref: Ref + + constructor() { + super() + + const extension = defineBasicExtension() + this.editor = createEditor({ extension }) + this.ref = createRef() + } + + override createRenderRoot() { + return this + } + + override disconnectedCallback() { + this.editor.unmount() + super.disconnectedCallback() + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.editor.mount(this.ref.value) + } + + override render() { + return html` +
+ ` + } +} + +export function registerLitEditor() { + if (customElements.get('lit-editor-example-minimal')) return + customElements.define('lit-editor-example-minimal', LitEditor) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-example-minimal': LitEditor + } +} diff --git a/lit-minimal/src/components/editor/examples/minimal/index.ts b/lit-minimal/src/components/editor/examples/minimal/index.ts new file mode 100644 index 0000000000..9eeecbbc50 --- /dev/null +++ b/lit-minimal/src/components/editor/examples/minimal/index.ts @@ -0,0 +1 @@ +export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-minimal/src/editor.ts b/lit-minimal/src/editor.ts new file mode 100644 index 0000000000..63bc2902d8 --- /dev/null +++ b/lit-minimal/src/editor.ts @@ -0,0 +1,18 @@ +import { registerLitEditor } from './components/editor/examples/minimal' +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +registerLitEditor() + +@customElement('my-editor') +export class MyEditor extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-minimal/tsconfig.json b/lit-minimal/tsconfig.json new file mode 100644 index 0000000000..f3ad657d5f --- /dev/null +++ b/lit-minimal/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es2023", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "esnext", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/lit-minimal/vite.config.ts b/lit-minimal/vite.config.ts new file mode 100644 index 0000000000..fb0cdf00b5 --- /dev/null +++ b/lit-minimal/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [tailwindcss()], +}) diff --git a/lit-slash-menu/.gitignore b/lit-slash-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/lit-slash-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/lit-slash-menu/README.md b/lit-slash-menu/README.md new file mode 100644 index 0000000000..1a4d660037 --- /dev/null +++ b/lit-slash-menu/README.md @@ -0,0 +1,15 @@ +# lit-slash-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-slash-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-slash-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/lit-slash-menu lit-slash-menu +cd lit-slash-menu +npm install +npm run dev +``` diff --git a/lit-slash-menu/index.html b/lit-slash-menu/index.html new file mode 100644 index 0000000000..9637b16269 --- /dev/null +++ b/lit-slash-menu/index.html @@ -0,0 +1,13 @@ + + + + + + ProseKit + Lit + + + + + + + diff --git a/lit-slash-menu/package.json b/lit-slash-menu/package.json new file mode 100644 index 0000000000..6bc4467a2a --- /dev/null +++ b/lit-slash-menu/package.json @@ -0,0 +1,24 @@ +{ + "name": "example-lit-slash-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "@lit/context": "^1.1.6", + "lit": "^3.3.2", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/lit-slash-menu/src/app.css b/lit-slash-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/lit-slash-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/lit-slash-menu/src/app.ts b/lit-slash-menu/src/app.ts new file mode 100644 index 0000000000..3cbf14f94d --- /dev/null +++ b/lit-slash-menu/src/app.ts @@ -0,0 +1,18 @@ +import './app.css' +import './editor' + +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +@customElement('my-app') +export class MyApp extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-slash-menu/src/components/editor/examples/slash-menu/editor.ts b/lit-slash-menu/src/components/editor/examples/slash-menu/editor.ts new file mode 100644 index 0000000000..10cbfbd1e1 --- /dev/null +++ b/lit-slash-menu/src/components/editor/examples/slash-menu/editor.ts @@ -0,0 +1,86 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { ContextProvider } from '@lit/context' +import { + html, + LitElement, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import { createRef, ref, type Ref } from 'lit/directives/ref.js' +import type { Editor } from 'prosekit/core' +import { createEditor } from 'prosekit/core' + +import { editorContext } from '../../ui/editor-context' +import { registerLitEditorSlashMenu } from '../../ui/slash-menu' + +import { defineExtension } from './extension' + +export class LitEditor extends LitElement { + static override properties = { + editor: { + state: true, + attribute: false, + } satisfies PropertyDeclaration, + } + + private editor: Editor + private ref: Ref + constructor() { + super() + + const extension = defineExtension() + this.editor = createEditor({ extension }) + this.ref = createRef() + new ContextProvider(this, { + context: editorContext, + initialValue: this.editor, + }) + } + + override createRenderRoot() { + return this + } + + override disconnectedCallback() { + this.editor.unmount() + super.disconnectedCallback() + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.editor.mount(this.ref.value) + } + + override render() { + return html` +
+
+
+ +
+
+ ` + } +} + +export function registerLitEditor() { + registerLitEditorSlashMenu() + + if (customElements.get('lit-editor-example-slash-menu')) return + customElements.define('lit-editor-example-slash-menu', LitEditor) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-example-slash-menu': LitEditor + } +} diff --git a/lit-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/lit-slash-menu/src/components/editor/examples/slash-menu/extension.ts new file mode 100644 index 0000000000..0edda60136 --- /dev/null +++ b/lit-slash-menu/src/components/editor/examples/slash-menu/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/lit-slash-menu/src/components/editor/examples/slash-menu/index.ts b/lit-slash-menu/src/components/editor/examples/slash-menu/index.ts new file mode 100644 index 0000000000..9eeecbbc50 --- /dev/null +++ b/lit-slash-menu/src/components/editor/examples/slash-menu/index.ts @@ -0,0 +1 @@ +export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-slash-menu/src/components/editor/ui/editor-context.ts b/lit-slash-menu/src/components/editor/ui/editor-context.ts new file mode 100644 index 0000000000..7af6d3a865 --- /dev/null +++ b/lit-slash-menu/src/components/editor/ui/editor-context.ts @@ -0,0 +1,6 @@ +import { createContext } from '@lit/context' +import type { Editor } from 'prosekit/core' + +export const editorContext = createContext( + 'prosekit-editor', +) diff --git a/lit-slash-menu/src/components/editor/ui/slash-menu/index.ts b/lit-slash-menu/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..9f49d0de7f --- /dev/null +++ b/lit-slash-menu/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { registerLitEditorSlashMenu } from './slash-menu' diff --git a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts new file mode 100644 index 0000000000..f2e0d5318d --- /dev/null +++ b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts @@ -0,0 +1,17 @@ +import { html, LitElement } from 'lit' + +export class SlashMenuEmptyElement extends LitElement { + override createRenderRoot() { + return this + } + + override render() { + return html` + + No results + + ` + } +} diff --git a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts new file mode 100644 index 0000000000..ad7bd23cf7 --- /dev/null +++ b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts @@ -0,0 +1,44 @@ +import { html, LitElement } from 'lit' + +export class SlashMenuItemElement extends LitElement { + static override properties = { + label: { type: String }, + kbd: { type: String }, + } + + label: string + kbd: string + + constructor() { + super() + this.label = '' + this.kbd = '' + } + + override createRenderRoot() { + return this + } + + // TODO: maybe this should changed to valueChange event?? + handleSelect = () => { + this.dispatchEvent(new CustomEvent('select')) + } + + override render() { + return html` + + ${this.label} + ${this.kbd + ? html` + + ${this.kbd} + + ` + : ''} + + ` + } +} diff --git a/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts new file mode 100644 index 0000000000..5b0eedb85d --- /dev/null +++ b/lit-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts @@ -0,0 +1,147 @@ +import { ContextConsumer } from '@lit/context' +import { html, LitElement } from 'lit' +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import { canUseRegexLookbehind } from 'prosekit/core' +import { + registerAutocompleteEmptyElement, + registerAutocompleteItemElement, + registerAutocompletePopupElement, + registerAutocompletePositionerElement, + registerAutocompleteRootElement, +} from 'prosekit/lit/autocomplete' + +import { editorContext } from '../editor-context' + +import { SlashMenuEmptyElement } from './slash-menu-empty' +import { SlashMenuItemElement } from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(? + | undefined + if (!editor) { + return html`` + } + + return html` + + + +
+ editor.commands.setParagraph()} + > + editor.commands.setHeading({ level: 1 })} + > + editor.commands.setHeading({ level: 2 })} + > + editor.commands.setHeading({ level: 3 })} + > + editor.commands.wrapInList({ kind: 'bullet' })} + > + editor.commands.wrapInList({ kind: 'ordered' })} + > + editor.commands.wrapInList({ kind: 'task' })} + > + editor.commands.wrapInList({ kind: 'toggle' })} + > + editor.commands.setBlockquote()} + > + editor.commands.insertTable({ row: 3, col: 3 })} + > + editor.commands.insertHorizontalRule()} + > + editor.commands.setCodeBlock()} + > + +
+
+
+
+ ` + } +} + +export function registerLitEditorSlashMenu() { + registerAutocompleteEmptyElement() + registerAutocompleteItemElement() + registerAutocompletePopupElement() + registerAutocompletePositionerElement() + registerAutocompleteRootElement() + + if (!customElements.get('lit-editor-slash-menu-item')) { + customElements.define('lit-editor-slash-menu-item', SlashMenuItemElement) + } + if (!customElements.get('lit-editor-slash-menu-empty')) { + customElements.define('lit-editor-slash-menu-empty', SlashMenuEmptyElement) + } + if (customElements.get('lit-editor-slash-menu')) return + customElements.define('lit-editor-slash-menu', SlashMenuElement) +} diff --git a/lit-slash-menu/src/editor.ts b/lit-slash-menu/src/editor.ts new file mode 100644 index 0000000000..7ea7548ab0 --- /dev/null +++ b/lit-slash-menu/src/editor.ts @@ -0,0 +1,18 @@ +import { registerLitEditor } from './components/editor/examples/slash-menu' +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +registerLitEditor() + +@customElement('my-editor') +export class MyEditor extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-slash-menu/tsconfig.json b/lit-slash-menu/tsconfig.json new file mode 100644 index 0000000000..f3ad657d5f --- /dev/null +++ b/lit-slash-menu/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es2023", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "esnext", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/lit-slash-menu/vite.config.ts b/lit-slash-menu/vite.config.ts new file mode 100644 index 0000000000..fb0cdf00b5 --- /dev/null +++ b/lit-slash-menu/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [tailwindcss()], +}) diff --git a/lit-table/.gitignore b/lit-table/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/lit-table/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/lit-table/README.md b/lit-table/README.md new file mode 100644 index 0000000000..72d736d130 --- /dev/null +++ b/lit-table/README.md @@ -0,0 +1,15 @@ +# lit-table + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-table) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-table) + +Run the example locally with: + +```bash +npx degit prosekit/examples/lit-table lit-table +cd lit-table +npm install +npm run dev +``` diff --git a/lit-table/index.html b/lit-table/index.html new file mode 100644 index 0000000000..9637b16269 --- /dev/null +++ b/lit-table/index.html @@ -0,0 +1,13 @@ + + + + + + ProseKit + Lit + + + + + + + diff --git a/lit-table/package.json b/lit-table/package.json new file mode 100644 index 0000000000..7d4054876d --- /dev/null +++ b/lit-table/package.json @@ -0,0 +1,24 @@ +{ + "name": "example-lit-table", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "@lit/context": "^1.1.6", + "lit": "^3.3.2", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/lit-table/src/app.css b/lit-table/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/lit-table/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/lit-table/src/app.ts b/lit-table/src/app.ts new file mode 100644 index 0000000000..3cbf14f94d --- /dev/null +++ b/lit-table/src/app.ts @@ -0,0 +1,18 @@ +import './app.css' +import './editor' + +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +@customElement('my-app') +export class MyApp extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-table/src/components/editor/examples/table/editor.ts b/lit-table/src/components/editor/examples/table/editor.ts new file mode 100644 index 0000000000..3b3f30c393 --- /dev/null +++ b/lit-table/src/components/editor/examples/table/editor.ts @@ -0,0 +1,96 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { ContextProvider } from '@lit/context' +import { + html, + LitElement, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import { createRef, ref, type Ref } from 'lit/directives/ref.js' +import type { Editor, NodeJSON } from 'prosekit/core' +import { createEditor } from 'prosekit/core' + +import { sampleContent } from '../../sample/sample-doc-table' +import { editorContext } from '../../ui/editor-context' +import { registerLitEditorTableHandle } from '../../ui/table-handle' + +import { defineExtension } from './extension' + +export class LitEditor extends LitElement { + static override properties = { + initialContent: { attribute: false } satisfies PropertyDeclaration< + NodeJSON | undefined + >, + } + + initialContent?: NodeJSON + + private editor?: Editor + private ref: Ref + + constructor() { + super() + this.ref = createRef() + } + + override createRenderRoot() { + return this + } + + override disconnectedCallback() { + this.editor?.unmount() + super.disconnectedCallback() + } + + override willUpdate() { + if (this.editor) { + return + } + + const extension = defineExtension() + this.editor = createEditor({ + extension, + defaultContent: this.initialContent ?? sampleContent, + }) + new ContextProvider(this, { + context: editorContext, + initialValue: this.editor, + }) + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.editor?.mount(this.ref.value) + } + + override render() { + return html` +
+
+
+ +
+
+ ` + } +} + +export function registerLitEditor() { + registerLitEditorTableHandle() + + if (customElements.get('lit-editor-example-table')) return + customElements.define('lit-editor-example-table', LitEditor) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-example-table': LitEditor + } +} diff --git a/lit-table/src/components/editor/examples/table/extension.ts b/lit-table/src/components/editor/examples/table/extension.ts new file mode 100644 index 0000000000..ee7b142041 --- /dev/null +++ b/lit-table/src/components/editor/examples/table/extension.ts @@ -0,0 +1,20 @@ +import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineTable(), + defineHistory(), + defineGapCursor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/lit-table/src/components/editor/examples/table/index.ts b/lit-table/src/components/editor/examples/table/index.ts new file mode 100644 index 0000000000..9eeecbbc50 --- /dev/null +++ b/lit-table/src/components/editor/examples/table/index.ts @@ -0,0 +1 @@ +export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-table/src/components/editor/sample/sample-doc-table.ts b/lit-table/src/components/editor/sample/sample-doc-table.ts new file mode 100644 index 0000000000..c737121672 --- /dev/null +++ b/lit-table/src/components/editor/sample/sample-doc-table.ts @@ -0,0 +1,174 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D1', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D2', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], +} diff --git a/lit-table/src/components/editor/ui/editor-context.ts b/lit-table/src/components/editor/ui/editor-context.ts new file mode 100644 index 0000000000..7af6d3a865 --- /dev/null +++ b/lit-table/src/components/editor/ui/editor-context.ts @@ -0,0 +1,6 @@ +import { createContext } from '@lit/context' +import type { Editor } from 'prosekit/core' + +export const editorContext = createContext( + 'prosekit-editor', +) diff --git a/lit-table/src/components/editor/ui/table-handle/index.ts b/lit-table/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..0b0e06268e --- /dev/null +++ b/lit-table/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { registerLitEditorTableHandle } from './table-handle' diff --git a/lit-table/src/components/editor/ui/table-handle/table-handle.ts b/lit-table/src/components/editor/ui/table-handle/table-handle.ts new file mode 100644 index 0000000000..b240b86e24 --- /dev/null +++ b/lit-table/src/components/editor/ui/table-handle/table-handle.ts @@ -0,0 +1,335 @@ +import { ContextConsumer } from '@lit/context' +import { + html, + LitElement, + nothing, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import type { Editor } from 'prosekit/core' +import { defineUpdateHandler } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { + registerMenuItemElement, + registerMenuPopupElement, + registerMenuPositionerElement, +} from 'prosekit/lit/menu' +import { + registerTableHandleColumnMenuRootElement, + registerTableHandleColumnMenuTriggerElement, + registerTableHandleColumnPopupElement, + registerTableHandleColumnPositionerElement, + registerTableHandleDragPreviewElement, + registerTableHandleDropIndicatorElement, + registerTableHandleRootElement, + registerTableHandleRowMenuRootElement, + registerTableHandleRowMenuTriggerElement, + registerTableHandleRowPopupElement, + registerTableHandleRowPositionerElement, +} from 'prosekit/lit/table-handle' + +import { editorContext } from '../editor-context' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +class LitTableHandle extends LitElement { + static override properties = { + dir: { type: String } satisfies PropertyDeclaration<'ltr' | 'rtl'>, + } + + override dir: string = '' + + private editorConsumer = new ContextConsumer(this, { + context: editorContext, + subscribe: true, + }) + + private removeUpdateExtension?: VoidFunction + + override createRenderRoot() { + return this + } + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + this.attachEditorListener() + } + + override disconnectedCallback() { + this.detachEditorListener() + super.disconnectedCallback() + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.attachEditorListener() + } + + private attachEditorListener() { + this.detachEditorListener() + + const editor = this.editorConsumer.value + if (!editor) return + + this.removeUpdateExtension = editor.use( + defineUpdateHandler(() => this.requestUpdate()), + ) + } + + private detachEditorListener() { + this.removeUpdateExtension?.() + this.removeUpdateExtension = undefined + } + + override render() { + const editor = this.editorConsumer.value as + | Editor + | undefined + if (!editor) { + return nothing + } + + const state = getTableHandleState(editor) + const placement = this.dir === 'rtl' ? 'right' : 'left' + + return html` + + + + + + + +
+
+ + + ${state.addTableColumnBefore.canExec + ? html` + + Insert Left + + ` + : nothing} + ${state.addTableColumnAfter.canExec + ? html` + + Insert Right + + ` + : nothing} + ${state.deleteCellSelection.canExec + ? html` + + Clear Contents + + Del + + + ` + : nothing} + ${state.deleteTableColumn.canExec + ? html` + + Delete Column + + ` + : nothing} + ${state.deleteTable.canExec + ? html` + + Delete Table + + ` + : nothing} + + +
+
+
+ + + + +
+
+ + + ${state.addTableRowAbove.canExec + ? html` + + Insert Above + + ` + : nothing} + ${state.addTableRowBelow.canExec + ? html` + + Insert Below + + ` + : nothing} + ${state.deleteCellSelection.canExec + ? html` + + Clear Contents + + Del + + + ` + : nothing} + ${state.deleteTableRow.canExec + ? html` + + Delete Row + + ` + : nothing} + ${state.deleteTable.canExec + ? html` + + Delete Table + + ` + : nothing} + + +
+
+
+
+ ` + } +} + +export function registerLitEditorTableHandle() { + registerMenuItemElement() + registerMenuPopupElement() + registerMenuPositionerElement() + registerTableHandleColumnMenuRootElement() + registerTableHandleColumnMenuTriggerElement() + registerTableHandleColumnPopupElement() + registerTableHandleColumnPositionerElement() + registerTableHandleDragPreviewElement() + registerTableHandleDropIndicatorElement() + registerTableHandleRootElement() + registerTableHandleRowMenuRootElement() + registerTableHandleRowMenuTriggerElement() + registerTableHandleRowPopupElement() + registerTableHandleRowPositionerElement() + + if (customElements.get('lit-editor-table-handle')) return + customElements.define('lit-editor-table-handle', LitTableHandle) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-table-handle': LitTableHandle + } +} diff --git a/lit-table/src/editor.ts b/lit-table/src/editor.ts new file mode 100644 index 0000000000..8ca4bad3e5 --- /dev/null +++ b/lit-table/src/editor.ts @@ -0,0 +1,18 @@ +import { registerLitEditor } from './components/editor/examples/table' +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +registerLitEditor() + +@customElement('my-editor') +export class MyEditor extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-table/tsconfig.json b/lit-table/tsconfig.json new file mode 100644 index 0000000000..f3ad657d5f --- /dev/null +++ b/lit-table/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es2023", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "esnext", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/lit-table/vite.config.ts b/lit-table/vite.config.ts new file mode 100644 index 0000000000..fb0cdf00b5 --- /dev/null +++ b/lit-table/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [tailwindcss()], +}) diff --git a/lit-toolbar/.gitignore b/lit-toolbar/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/lit-toolbar/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/lit-toolbar/README.md b/lit-toolbar/README.md new file mode 100644 index 0000000000..6f77188cb3 --- /dev/null +++ b/lit-toolbar/README.md @@ -0,0 +1,15 @@ +# lit-toolbar + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/lit-toolbar) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/lit-toolbar) + +Run the example locally with: + +```bash +npx degit prosekit/examples/lit-toolbar lit-toolbar +cd lit-toolbar +npm install +npm run dev +``` diff --git a/lit-toolbar/index.html b/lit-toolbar/index.html new file mode 100644 index 0000000000..9637b16269 --- /dev/null +++ b/lit-toolbar/index.html @@ -0,0 +1,13 @@ + + + + + + ProseKit + Lit + + + + + + + diff --git a/lit-toolbar/package.json b/lit-toolbar/package.json new file mode 100644 index 0000000000..1607a80714 --- /dev/null +++ b/lit-toolbar/package.json @@ -0,0 +1,24 @@ +{ + "name": "example-lit-toolbar", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "@lit/context": "^1.1.6", + "lit": "^3.3.2", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/lit-toolbar/src/app.css b/lit-toolbar/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/lit-toolbar/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/lit-toolbar/src/app.ts b/lit-toolbar/src/app.ts new file mode 100644 index 0000000000..3cbf14f94d --- /dev/null +++ b/lit-toolbar/src/app.ts @@ -0,0 +1,18 @@ +import './app.css' +import './editor' + +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +@customElement('my-app') +export class MyApp extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-toolbar/src/components/editor/examples/toolbar/editor.ts b/lit-toolbar/src/components/editor/examples/toolbar/editor.ts new file mode 100644 index 0000000000..5991536124 --- /dev/null +++ b/lit-toolbar/src/components/editor/examples/toolbar/editor.ts @@ -0,0 +1,85 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { ContextProvider } from '@lit/context' +import { + html, + LitElement, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import { createRef, ref, type Ref } from 'lit/directives/ref.js' +import type { Editor } from 'prosekit/core' +import { createEditor } from 'prosekit/core' + +import { sampleUploader } from '../../sample/sample-uploader' +import { editorContext } from '../../ui/editor-context' +import { registerLitEditorToolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export class LitEditor extends LitElement { + static override properties = { + editor: { + state: true, + attribute: false, + } satisfies PropertyDeclaration, + } + + private editor: Editor + private ref: Ref + constructor() { + super() + + const extension = defineExtension() + this.editor = createEditor({ extension }) + this.ref = createRef() + new ContextProvider(this, { + context: editorContext, + initialValue: this.editor, + }) + } + + override createRenderRoot() { + return this + } + + override disconnectedCallback() { + this.editor.unmount() + super.disconnectedCallback() + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.editor.mount(this.ref.value) + } + + override render() { + return html` +
+ +
+
+
+
+ ` + } +} + +export function registerLitEditor() { + registerLitEditorToolbar() + + if (customElements.get('lit-editor-example-toolbar')) return + customElements.define('lit-editor-example-toolbar', LitEditor) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-example-toolbar': LitEditor + } +} diff --git a/lit-toolbar/src/components/editor/examples/toolbar/extension.ts b/lit-toolbar/src/components/editor/examples/toolbar/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/lit-toolbar/src/components/editor/examples/toolbar/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/lit-toolbar/src/components/editor/examples/toolbar/index.ts b/lit-toolbar/src/components/editor/examples/toolbar/index.ts new file mode 100644 index 0000000000..9eeecbbc50 --- /dev/null +++ b/lit-toolbar/src/components/editor/examples/toolbar/index.ts @@ -0,0 +1 @@ +export { LitEditor as ExampleEditor, registerLitEditor } from './editor' diff --git a/lit-toolbar/src/components/editor/sample/sample-uploader.ts b/lit-toolbar/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/lit-toolbar/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/lit-toolbar/src/components/editor/ui/button/button.ts b/lit-toolbar/src/components/editor/ui/button/button.ts new file mode 100644 index 0000000000..aef47e4e1f --- /dev/null +++ b/lit-toolbar/src/components/editor/ui/button/button.ts @@ -0,0 +1,92 @@ +import { html, LitElement, nothing, type PropertyDeclaration } from 'lit' +import { + registerTooltipPopupElement, + registerTooltipPositionerElement, + registerTooltipRootElement, + registerTooltipTriggerElement, +} from 'prosekit/lit/tooltip' + +class LitButton extends LitElement { + static override properties = { + pressed: { type: Boolean }, + disabled: { type: Boolean }, + tooltip: { type: String }, + icon: { type: String }, + } satisfies Record + + pressed = false + disabled = false + tooltip = '' + icon = '' + + override createRenderRoot() { + return this + } + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + } + + private handleMouseDown = (event: MouseEvent) => { + // Prevent the editor from being blurred when the button is clicked + event.preventDefault() + } + + override render() { + const tooltip = this.tooltip + + return html` + + + + + ${tooltip + ? html` + + + ${tooltip} + + + ` + : nothing} + + ` + } +} + +export function registerLitEditorButton() { + registerTooltipPopupElement() + registerTooltipPositionerElement() + registerTooltipRootElement() + registerTooltipTriggerElement() + + if (customElements.get('lit-editor-button')) return + customElements.define('lit-editor-button', LitButton) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-button': LitButton + } +} diff --git a/lit-toolbar/src/components/editor/ui/button/index.ts b/lit-toolbar/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..02efbeadd2 --- /dev/null +++ b/lit-toolbar/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { registerLitEditorButton } from './button' diff --git a/lit-toolbar/src/components/editor/ui/editor-context.ts b/lit-toolbar/src/components/editor/ui/editor-context.ts new file mode 100644 index 0000000000..7af6d3a865 --- /dev/null +++ b/lit-toolbar/src/components/editor/ui/editor-context.ts @@ -0,0 +1,6 @@ +import { createContext } from '@lit/context' +import type { Editor } from 'prosekit/core' + +export const editorContext = createContext( + 'prosekit-editor', +) diff --git a/lit-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.ts b/lit-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.ts new file mode 100644 index 0000000000..3a129e53de --- /dev/null +++ b/lit-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.ts @@ -0,0 +1,200 @@ +import { html, LitElement, nothing, type PropertyDeclaration } from 'lit' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { + registerPopoverPopupElement, + registerPopoverPositionerElement, + registerPopoverRootElement, + registerPopoverTriggerElement, + type OpenChangeEvent, +} from 'prosekit/lit/popover' + +import { registerLitEditorButton } from '../button' + +let imageUploadId = 0 + +class LitImageUploadPopover extends LitElement { + static override properties = { + editor: { attribute: false } satisfies PropertyDeclaration, + uploader: { attribute: false } satisfies PropertyDeclaration< + Uploader + >, + tooltip: { type: String }, + disabled: { type: Boolean }, + icon: { type: String }, + } + + editor?: Editor + uploader?: Uploader + tooltip = '' + disabled = false + icon = '' + + private open = false + private url = '' + private file: File | null = null + private ariaId = `lit-image-upload-${imageUploadId++}` + + override createRenderRoot() { + return this + } + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + } + + private handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + this.deferResetState() + } + + this.open = event.detail + this.requestUpdate() + } + + private handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + this.file = selectedFile + this.url = '' + } else { + this.file = null + } + + this.requestUpdate() + } + + private handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + this.url = inputUrl + this.file = null + } else { + this.url = '' + } + + this.requestUpdate() + } + + private deferResetState() { + setTimeout(() => { + this.url = '' + this.file = null + this.requestUpdate() + }, 300) + } + + private handleSubmit = () => { + const editor = this.editor + if (!editor) return + + if (this.url) { + editor.commands.insertImage({ src: this.url }) + } else if (this.file && this.uploader) { + editor.commands.uploadImage({ file: this.file, uploader: this.uploader }) + } + + this.open = false + this.deferResetState() + this.requestUpdate() + } + + override render() { + return html` + + + + + + + + ${!this.file + ? html` + + + ` + : nothing} + ${!this.url + ? html` + + + ` + : nothing} + ${this.url + ? html` + + ` + : nothing} + ${this.file + ? html` + + ` + : nothing} + + + + ` + } +} + +export function registerLitEditorImageUploadPopover() { + registerLitEditorButton() + registerPopoverPopupElement() + registerPopoverPositionerElement() + registerPopoverRootElement() + registerPopoverTriggerElement() + + if (customElements.get('lit-editor-image-upload-popover')) return + customElements.define( + 'lit-editor-image-upload-popover', + LitImageUploadPopover, + ) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-image-upload-popover': LitImageUploadPopover + } +} diff --git a/lit-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/lit-toolbar/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ff00f20c86 --- /dev/null +++ b/lit-toolbar/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { registerLitEditorImageUploadPopover } from './image-upload-popover' diff --git a/lit-toolbar/src/components/editor/ui/toolbar/index.ts b/lit-toolbar/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..6d6df28ea4 --- /dev/null +++ b/lit-toolbar/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { registerLitEditorToolbar } from './toolbar' diff --git a/lit-toolbar/src/components/editor/ui/toolbar/toolbar.ts b/lit-toolbar/src/components/editor/ui/toolbar/toolbar.ts new file mode 100644 index 0000000000..ee46ea40a1 --- /dev/null +++ b/lit-toolbar/src/components/editor/ui/toolbar/toolbar.ts @@ -0,0 +1,467 @@ +import { ContextConsumer } from '@lit/context' +import { + html, + LitElement, + nothing, + type PropertyDeclaration, + type PropertyValues, +} from 'lit' +import type { BasicExtension } from 'prosekit/basic' +import { defineUpdateHandler, type Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' + +import { registerLitEditorButton } from '../button' +import { editorContext } from '../editor-context' +import { registerLitEditorImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +class LitToolbar extends LitElement { + static override properties = { + uploader: { attribute: false } satisfies PropertyDeclaration< + Uploader + >, + } + + uploader?: Uploader + + private editorConsumer = new ContextConsumer(this, { + context: editorContext, + subscribe: true, + }) + + private removeUpdateExtension?: VoidFunction + + override createRenderRoot() { + return this + } + + override connectedCallback() { + super.connectedCallback() + this.classList.add('contents') + this.attachEditorListener() + } + + override disconnectedCallback() { + this.detachEditorListener() + super.disconnectedCallback() + } + + override updated(changedProperties: PropertyValues) { + super.updated(changedProperties) + this.attachEditorListener() + } + + private attachEditorListener() { + this.detachEditorListener() + + const editor = this.editorConsumer.value + if (!editor) return + + this.removeUpdateExtension = editor.use( + defineUpdateHandler(() => this.requestUpdate()), + ) + } + + private detachEditorListener() { + this.removeUpdateExtension?.() + this.removeUpdateExtension = undefined + } + + override render() { + const editor = this.editorConsumer.value as + | Editor + | undefined + if (!editor) { + return nothing + } + + const items = getToolbarItems(editor) + + return html` +
+ ${items.undo + ? html` + + ` + : nothing} + ${items.redo + ? html` + + ` + : nothing} + ${items.bold + ? html` + + ` + : nothing} + ${items.italic + ? html` + + ` + : nothing} + ${items.underline + ? html` + + ` + : nothing} + ${items.strike + ? html` + + ` + : nothing} + ${items.code + ? html` + + ` + : nothing} + ${items.codeBlock + ? html` + + ` + : nothing} + ${items.heading1 + ? html` + + ` + : nothing} + ${items.heading2 + ? html` + + ` + : nothing} + ${items.heading3 + ? html` + + ` + : nothing} + ${items.horizontalRule + ? html` + + ` + : nothing} + ${items.blockquote + ? html` + + ` + : nothing} + ${items.bulletList + ? html` + + ` + : nothing} + ${items.orderedList + ? html` + + ` + : nothing} + ${items.taskList + ? html` + + ` + : nothing} + ${items.toggleList + ? html` + + ` + : nothing} + ${items.indentList + ? html` + + ` + : nothing} + ${items.dedentList + ? html` + + ` + : nothing} + ${this.uploader && items.insertImage + ? html` + + ` + : nothing} +
+ ` + } +} + +export function registerLitEditorToolbar() { + registerLitEditorButton() + registerLitEditorImageUploadPopover() + + if (customElements.get('lit-editor-toolbar')) return + customElements.define('lit-editor-toolbar', LitToolbar) +} + +declare global { + interface HTMLElementTagNameMap { + 'lit-editor-toolbar': LitToolbar + } +} diff --git a/lit-toolbar/src/editor.ts b/lit-toolbar/src/editor.ts new file mode 100644 index 0000000000..6eed3b2649 --- /dev/null +++ b/lit-toolbar/src/editor.ts @@ -0,0 +1,18 @@ +import { registerLitEditor } from './components/editor/examples/toolbar' +import { LitElement, html } from 'lit' +import { customElement } from 'lit/decorators.js' + +registerLitEditor() + +@customElement('my-editor') +export class MyEditor extends LitElement { + createRenderRoot() { + return this + } + + render() { + return html` + + ` + } +} diff --git a/lit-toolbar/tsconfig.json b/lit-toolbar/tsconfig.json new file mode 100644 index 0000000000..f3ad657d5f --- /dev/null +++ b/lit-toolbar/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "es2023", + "experimentalDecorators": true, + "useDefineForClassFields": false, + "module": "esnext", + "lib": ["ES2023", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/lit-toolbar/vite.config.ts b/lit-toolbar/vite.config.ts new file mode 100644 index 0000000000..fb0cdf00b5 --- /dev/null +++ b/lit-toolbar/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [tailwindcss()], +}) diff --git a/next-full/.gitignore b/next-full/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/next-full/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/next-full/README.md b/next-full/README.md new file mode 100644 index 0000000000..ee0d54d4fa --- /dev/null +++ b/next-full/README.md @@ -0,0 +1,15 @@ +# next-full + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/next-full) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/next-full) + +Run the example locally with: + +```bash +npx degit prosekit/examples/next-full next-full +cd next-full +npm install +npm run dev +``` diff --git a/next-full/app/app.css b/next-full/app/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/next-full/app/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/next-full/app/layout.tsx b/next-full/app/layout.tsx new file mode 100644 index 0000000000..42ac1c6fe4 --- /dev/null +++ b/next-full/app/layout.tsx @@ -0,0 +1,22 @@ +import type { Metadata } from 'next' +import { Inter } from 'next/font/google' +import './app.css' + +const inter = Inter({ subsets: ['latin'] }) + +export const metadata: Metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + return ( + + {children} + + ) +} diff --git a/next-full/app/page.tsx b/next-full/app/page.tsx new file mode 100644 index 0000000000..e96a9ac6b5 --- /dev/null +++ b/next-full/app/page.tsx @@ -0,0 +1,9 @@ +import Editor from '@/components/editor-dynamic' + +export default function Home() { + return ( +
+ +
+ ) +} diff --git a/next-full/components/editor-dynamic.tsx b/next-full/components/editor-dynamic.tsx new file mode 100644 index 0000000000..beb742d59a --- /dev/null +++ b/next-full/components/editor-dynamic.tsx @@ -0,0 +1,15 @@ +'use client' + +import dynamic from 'next/dynamic' + +const EditorLazy = dynamic( + async () => { + const { ExampleEditor } = await import('./editor/examples/full') + return { default: ExampleEditor } + }, + { ssr: false }, +) + +export default function Editor() { + return +} diff --git a/next-full/components/editor/examples/full/editor.tsx b/next-full/components/editor/examples/full/editor.tsx new file mode 100644 index 0000000000..d49fac1be9 --- /dev/null +++ b/next-full/components/editor/examples/full/editor.tsx @@ -0,0 +1,56 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-full' +import { tags } from '../../sample/sample-tag-data' +import { sampleUploader } from '../../sample/sample-uploader' +import { users } from '../../sample/sample-user-data' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' +import { InlineMenu } from '../../ui/inline-menu' +import { SlashMenu } from '../../ui/slash-menu' +import { TableHandle } from '../../ui/table-handle' +import { TagMenu } from '../../ui/tag-menu' +import { Toolbar } from '../../ui/toolbar' +import { UserMenu } from '../../ui/user-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+ + + + + + + +
+
+
+ ) +} diff --git a/next-full/components/editor/examples/full/extension.ts b/next-full/components/editor/examples/full/extension.ts new file mode 100644 index 0000000000..5fc2f60685 --- /dev/null +++ b/next-full/components/editor/examples/full/extension.ts @@ -0,0 +1,34 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineImageUploadHandler } from 'prosekit/extensions/image' +import { defineMath } from 'prosekit/extensions/math' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' +import { sampleUploader } from '../../sample/sample-uploader' +import { defineCodeBlockView } from '../../ui/code-block-view' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + defineMention(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + defineCodeBlockShiki(), + defineHorizontalRule(), + defineCodeBlockView(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/next-full/components/editor/examples/full/html.ts b/next-full/components/editor/examples/full/html.ts new file mode 100644 index 0000000000..4945ec9108 --- /dev/null +++ b/next-full/components/editor/examples/full/html.ts @@ -0,0 +1,35 @@ +import { createEditor, type NodeJSON } from 'prosekit/core' + +import { sampleContent } from '../../sample/sample-doc-full' + +import { defineExtension } from './extension' + +/** + * Renders a ProseMirror document JSON object to an HTML string. + * + * This is useful for server-side rendering. + * + * @example + * + * ```js + * import { JSDOM } from 'jsdom' + * const dom = new JSDOM('') + * const document = dom.window.document + * const html = renderHTML(document, myContentJSON) + * ``` + */ +export function renderHTML( + document: Document, + content: NodeJSON = sampleContent, +): string { + const extension = defineExtension() + const editor = createEditor({ extension }) + editor.setContent(content) + const html: string = editor.getDocHTML({ document }) + if (html.startsWith('
') && html.endsWith('
')) { + return html.slice(5, -6) // Remove the wrapping
tags + } else { + console.error('Unexpected HTML format: expected a single
wrapper') + return html + } +} diff --git a/next-full/components/editor/examples/full/index.ts b/next-full/components/editor/examples/full/index.ts new file mode 100644 index 0000000000..516b54a1f0 --- /dev/null +++ b/next-full/components/editor/examples/full/index.ts @@ -0,0 +1,2 @@ +export { default as ExampleEditor } from './editor' +export { renderHTML } from './html' diff --git a/next-full/components/editor/sample/katex.ts b/next-full/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/next-full/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/next-full/components/editor/sample/sample-doc-full.ts b/next-full/components/editor/sample/sample-doc-full.ts new file mode 100644 index 0000000000..13e49b634d --- /dev/null +++ b/next-full/components/editor/sample/sample-doc-full.ts @@ -0,0 +1,442 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'The editor that thinks like you' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', + }, + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'writing without barriers', + }, + { type: 'text', text: '.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Text that shines.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Make your words ' }, + { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, + { type: 'text', text: ', or ' }, + { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, + { type: 'text', text: '. Add ' }, + { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, + { type: 'text', text: ' that stands out. Create ' }, + { + type: 'text', + marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], + text: 'links', + }, + { type: 'text', text: ' that connect.' }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Select any text to format it. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '@' }, + { type: 'text', text: ' to mention ' }, + { + type: 'mention', + attrs: { id: '39', value: '@someone', kind: 'user' }, + }, + { type: 'text', text: ' or ' }, + { type: 'text', marks: [{ type: 'code' }], text: '#' }, + { type: 'text', text: ' for ' }, + { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, + { type: 'text', text: '. Press ' }, + { type: 'text', marks: [{ type: 'code' }], text: '/' }, + { type: 'text', text: " and discover what's possible." }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Lists that organize.' }], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Bullet points that guide thoughts' }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Nested lists for complex ideas' }], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sub-points flow naturally' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Tasks that focus' }], + }, + { + type: 'list', + attrs: { kind: 'task', order: null, checked: true, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Done feels good' }], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Todo drives action' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Numbered steps' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sequential thinking' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Clear progress' }], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Code that inspires.' }], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Images that captivate.' }], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/season/320x240/107', + }, + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the handle in the bottom right corner to resize.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Tables that structure.' }], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'Feature', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'How to use', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Format text' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Select and choose' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Perfect styling' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Add mentions' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Type @ and name' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Connected ideas' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Insert anything' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Press / for menu' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Endless possibilities' }], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Math that renders.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Inline math like ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' appears within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Quotes that inspire.' }], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: '"This is not just an editor. This is how writing should feel."', + }, + ], + }, + ], + }, + { type: 'horizontalRule' }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Start typing. Everything else just flows.' }, + ], + }, + ], +} diff --git a/next-full/components/editor/sample/sample-tag-data.ts b/next-full/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/next-full/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/next-full/components/editor/sample/sample-uploader.ts b/next-full/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/next-full/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/next-full/components/editor/sample/sample-user-data.ts b/next-full/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/next-full/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/next-full/components/editor/ui/block-handle/block-handle.tsx b/next-full/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..3cc6028d5c --- /dev/null +++ b/next-full/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,33 @@ +'use client' + +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/react/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/next-full/components/editor/ui/block-handle/index.ts b/next-full/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/next-full/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/next-full/components/editor/ui/button/button.tsx b/next-full/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/next-full/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/next-full/components/editor/ui/button/index.ts b/next-full/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/next-full/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/next-full/components/editor/ui/code-block-view/code-block-view.tsx b/next-full/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..f6c0428091 --- /dev/null +++ b/next-full/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,39 @@ +'use client' + +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { ReactNodeViewProps } from 'prosekit/react' + +export default function CodeBlockView(props: ReactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/next-full/components/editor/ui/code-block-view/index.ts b/next-full/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..b7e6b996bc
--- /dev/null
+++ b/next-full/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineReactNodeView,
+  type ReactNodeViewComponent,
+} from 'prosekit/react'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineReactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies ReactNodeViewComponent,
+  })
+}
diff --git a/next-full/components/editor/ui/drop-indicator/drop-indicator.tsx b/next-full/components/editor/ui/drop-indicator/drop-indicator.tsx
new file mode 100644
index 0000000000..87c1746622
--- /dev/null
+++ b/next-full/components/editor/ui/drop-indicator/drop-indicator.tsx
@@ -0,0 +1,7 @@
+'use client'
+
+import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator'
+
+export default function DropIndicator() {
+  return 
+}
diff --git a/next-full/components/editor/ui/drop-indicator/index.ts b/next-full/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..f8fb7139c4
--- /dev/null
+++ b/next-full/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator'
diff --git a/next-full/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/next-full/components/editor/ui/image-upload-popover/image-upload-popover.tsx
new file mode 100644
index 0000000000..808361b6ad
--- /dev/null
+++ b/next-full/components/editor/ui/image-upload-popover/image-upload-popover.tsx
@@ -0,0 +1,145 @@
+'use client'
+
+import type { Uploader } from 'prosekit/extensions/file'
+import type { ImageExtension } from 'prosekit/extensions/image'
+import { useEditor } from 'prosekit/react'
+import {
+  PopoverPopup,
+  PopoverPositioner,
+  PopoverRoot,
+  PopoverTrigger,
+} from 'prosekit/react/popover'
+import type { OpenChangeEvent } from 'prosekit/web/popover'
+import { useId, useState, type ReactNode } from 'react'
+
+import { Button } from '../button'
+
+export default function ImageUploadPopover(props: {
+  uploader: Uploader
+  tooltip: string
+  disabled: boolean
+  children: ReactNode
+}) {
+  const [open, setOpen] = useState(false)
+  const [url, setUrl] = useState('')
+  const [file, setFile] = useState(null)
+  const ariaId = useId()
+
+  const editor = useEditor()
+
+  const handleFileChange: React.ChangeEventHandler = (
+    event,
+  ) => {
+    const file = event.target.files?.[0]
+
+    if (file) {
+      setFile(file)
+      setUrl('')
+    } else {
+      setFile(null)
+    }
+  }
+
+  const handleUrlChange: React.ChangeEventHandler = (
+    event,
+  ) => {
+    const url = event.target.value
+
+    if (url) {
+      setUrl(url)
+      setFile(null)
+    } else {
+      setUrl('')
+    }
+  }
+
+  const deferResetState = () => {
+    setTimeout(() => {
+      setUrl('')
+      setFile(null)
+    }, 300)
+  }
+
+  const handleSubmit = () => {
+    if (url) {
+      editor.commands.insertImage({ src: url })
+    } else if (file) {
+      editor.commands.uploadImage({ file, uploader: props.uploader })
+    }
+    setOpen(false)
+    deferResetState()
+  }
+
+  const handleOpenChange = (event: OpenChangeEvent) => {
+    if (!event.detail) {
+      deferResetState()
+    }
+    setOpen(event.detail)
+  }
+
+  return (
+    
+      
+        
+      
+
+      
+        
+          {file ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? (
+            
+          ) : null}
+
+          {file ? (
+            
+          ) : null}
+        
+      
+    
+  )
+}
diff --git a/next-full/components/editor/ui/image-upload-popover/index.ts b/next-full/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..5d49d873ce
--- /dev/null
+++ b/next-full/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/next-full/components/editor/ui/image-view/image-view.tsx b/next-full/components/editor/ui/image-view/image-view.tsx
new file mode 100644
index 0000000000..06da475774
--- /dev/null
+++ b/next-full/components/editor/ui/image-view/image-view.tsx
@@ -0,0 +1,94 @@
+'use client'
+
+import { UploadTask } from 'prosekit/extensions/file'
+import type { ImageAttrs } from 'prosekit/extensions/image'
+import type { ReactNodeViewProps } from 'prosekit/react'
+import { ResizableHandle, ResizableRoot } from 'prosekit/react/resizable'
+import { useEffect, useState, type SyntheticEvent } from 'react'
+
+export default function ImageView(props: ReactNodeViewProps) {
+  const attrs = props.node.attrs as ImageAttrs
+  const url = attrs.src || ''
+  const uploading = url.startsWith('blob:')
+
+  const [aspectRatio, setAspectRatio] = useState()
+  const [error, setError] = useState()
+  const [progress, setProgress] = useState(0)
+
+  useEffect(() => {
+    if (!uploading) return
+
+    const uploadTask = UploadTask.get(url)
+    if (!uploadTask) return
+
+    let canceled = false
+
+    uploadTask.finished.catch((error) => {
+      if (canceled) return
+      setError(String(error))
+    })
+    const unsubscribeProgress = uploadTask.subscribeProgress(
+      ({ loaded, total }) => {
+        if (canceled) return
+        setProgress(total ? loaded / total : 0)
+      },
+    )
+
+    return () => {
+      canceled = true
+      unsubscribeProgress()
+    }
+  }, [url, uploading])
+
+  const handleImageLoad = (event: SyntheticEvent) => {
+    const img = event.target as HTMLImageElement
+    const { naturalWidth, naturalHeight } = img
+    const ratio = naturalWidth / naturalHeight
+    if (ratio && Number.isFinite(ratio)) {
+      setAspectRatio(ratio)
+    }
+    if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) {
+      props.setAttrs({ width: naturalWidth, height: naturalHeight })
+    }
+  }
+
+  return (
+     props.setAttrs(event.detail)}
+      data-selected={props.selected ? '' : undefined}
+      className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid"
+    >
+      {url && !error && (
+        upload preview
+      )}
+      {uploading && !error && (
+        
+
+
{Math.round(progress * 100)}%
+
+ )} + {error && ( +
+
+
+ Failed to upload image +
+
+ )} + +
+
+
+ ) +} diff --git a/next-full/components/editor/ui/image-view/index.ts b/next-full/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..c4a95f9d3f --- /dev/null +++ b/next-full/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + defineReactNodeView, + type ReactNodeViewComponent, +} from 'prosekit/react' + +import ImageView from './image-view' + +export function defineImageView(): Extension { + return defineReactNodeView({ + name: 'image', + component: ImageView satisfies ReactNodeViewComponent, + }) +} diff --git a/next-full/components/editor/ui/inline-menu/index.ts b/next-full/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/next-full/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/next-full/components/editor/ui/inline-menu/inline-menu.tsx b/next-full/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..af1b2bb2b7 --- /dev/null +++ b/next-full/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/react' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/react/inline-popover' +import { useState } from 'react' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/next-full/components/editor/ui/slash-menu/index.ts b/next-full/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/next-full/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/next-full/components/editor/ui/slash-menu/slash-menu-empty.tsx b/next-full/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..d0dca0934a --- /dev/null +++ b/next-full/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,11 @@ +'use client' + +import { AutocompleteEmpty } from 'prosekit/react/autocomplete' + +export default function SlashMenuEmpty() { + return ( + + No results + + ) +} diff --git a/next-full/components/editor/ui/slash-menu/slash-menu-item.tsx b/next-full/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..349c6e8924 --- /dev/null +++ b/next-full/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,23 @@ +'use client' + +import { AutocompleteItem } from 'prosekit/react/autocomplete' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}) { + return ( + + {props.label} + {props.kbd && ( + + {props.kbd} + + )} + + ) +} diff --git a/next-full/components/editor/ui/slash-menu/slash-menu.tsx b/next-full/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..3738f51aab --- /dev/null +++ b/next-full/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,102 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/react' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor.commands.setParagraph()} + /> + + editor.commands.setHeading({ level: 1 })} + /> + + editor.commands.setHeading({ level: 2 })} + /> + + editor.commands.setHeading({ level: 3 })} + /> + + editor.commands.wrapInList({ kind: 'bullet' })} + /> + + editor.commands.wrapInList({ kind: 'ordered' })} + /> + + editor.commands.wrapInList({ kind: 'task' })} + /> + + editor.commands.wrapInList({ kind: 'toggle' })} + /> + + editor.commands.setBlockquote()} + /> + + editor.commands.insertTable({ row: 3, col: 3 })} + /> + + editor.commands.insertHorizontalRule()} + /> + + editor.commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/next-full/components/editor/ui/table-handle/index.ts b/next-full/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/next-full/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/next-full/components/editor/ui/table-handle/table-handle.tsx b/next-full/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..b90b351382 --- /dev/null +++ b/next-full/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,188 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/react' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/react/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/react/table-handle' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props) { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + {state.addTableColumnBefore.canExec && ( + + Insert Left + + )} + {state.addTableColumnAfter.canExec && ( + + Insert Right + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableColumn.canExec && ( + + Delete Column + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+ + + + +
+
+ + + {state.addTableRowAbove.canExec && ( + + Insert Above + + )} + {state.addTableRowBelow.canExec && ( + + Insert Below + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableRow.canExec && ( + + Delete Row + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+
+ ) +} diff --git a/next-full/components/editor/ui/tag-menu/index.ts b/next-full/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..d344b33a70 --- /dev/null +++ b/next-full/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu' diff --git a/next-full/components/editor/ui/tag-menu/tag-menu.tsx b/next-full/components/editor/ui/tag-menu/tag-menu.tsx new file mode 100644 index 0000000000..711486fcf7 --- /dev/null +++ b/next-full/components/editor/ui/tag-menu/tag-menu.tsx @@ -0,0 +1,54 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/react' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +const regex = /#[\da-z]*$/i + +export default function TagMenu(props: { + tags: { id: number; label: string }[] +}) { + const editor = useEditor>() + + const handleTagInsert = (id: number, label: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '#' + label, + kind: 'tag', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + + + +
+ + No results + + + {props.tags.map((tag) => ( + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + ))} +
+
+
+
+ ) +} diff --git a/next-full/components/editor/ui/toolbar/index.ts b/next-full/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/next-full/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/next-full/components/editor/ui/toolbar/toolbar.tsx b/next-full/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/next-full/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/next-full/components/editor/ui/user-menu/index.ts b/next-full/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/next-full/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/next-full/components/editor/ui/user-menu/user-menu.tsx b/next-full/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..46555f6382 --- /dev/null +++ b/next-full/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,64 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/react' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}) { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + {props.users.map((user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + ))} +
+
+
+
+ ) +} diff --git a/next-full/next.config.mjs b/next-full/next.config.mjs new file mode 100644 index 0000000000..1d6147825a --- /dev/null +++ b/next-full/next.config.mjs @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {} + +export default nextConfig diff --git a/next-full/package.json b/next-full/package.json new file mode 100644 index 0000000000..2e6f61f122 --- /dev/null +++ b/next-full/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-next-full", + "version": "0.0.0", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev", + "lint": "next lint", + "start": "next start" + }, + "dependencies": { + "katex": "^0.16.47", + "next": "^16.2.6", + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/postcss": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "postcss": "^8.5.14", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3" + } +} diff --git a/next-full/postcss.config.mjs b/next-full/postcss.config.mjs new file mode 100644 index 0000000000..a869506ee4 --- /dev/null +++ b/next-full/postcss.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: { + '@tailwindcss/postcss': {}, + }, +} + +export default config diff --git a/next-full/tsconfig.json b/next-full/tsconfig.json new file mode 100644 index 0000000000..98dc46c300 --- /dev/null +++ b/next-full/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "ES2018", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/nuxt-full/.gitignore b/nuxt-full/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/nuxt-full/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/nuxt-full/README.md b/nuxt-full/README.md new file mode 100644 index 0000000000..32dc0f77a8 --- /dev/null +++ b/nuxt-full/README.md @@ -0,0 +1,15 @@ +# nuxt-full + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/nuxt-full) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/nuxt-full) + +Run the example locally with: + +```bash +npx degit prosekit/examples/nuxt-full nuxt-full +cd nuxt-full +npm install +npm run dev +``` diff --git a/nuxt-full/nuxt.config.ts b/nuxt-full/nuxt.config.ts new file mode 100644 index 0000000000..0443b74087 --- /dev/null +++ b/nuxt-full/nuxt.config.ts @@ -0,0 +1,12 @@ +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + devtools: { enabled: true }, + css: ['~/app.css'], + srcDir: 'src', + postcss: { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, + }, +}) diff --git a/nuxt-full/package.json b/nuxt-full/package.json new file mode 100644 index 0000000000..63ec921b50 --- /dev/null +++ b/nuxt-full/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-nuxt-full", + "private": true, + "type": "module", + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev", + "generate": "nuxt generate", + "postinstall": "nuxt prepare", + "preview": "nuxt preview" + }, + "dependencies": { + "katex": "^0.16.47", + "nuxt": "^4.4.5", + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/postcss": "^4.3.0", + "autoprefixer": "^10.5.0", + "postcss": "^8.5.14", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3" + } +} diff --git a/nuxt-full/src/app.css b/nuxt-full/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/nuxt-full/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/nuxt-full/src/app.vue b/nuxt-full/src/app.vue new file mode 100644 index 0000000000..8c4decdebf --- /dev/null +++ b/nuxt-full/src/app.vue @@ -0,0 +1,12 @@ + + + diff --git a/nuxt-full/src/components/editor/examples/full/editor.vue b/nuxt-full/src/components/editor/examples/full/editor.vue new file mode 100644 index 0000000000..a81ba14ef8 --- /dev/null +++ b/nuxt-full/src/components/editor/examples/full/editor.vue @@ -0,0 +1,53 @@ + + + diff --git a/nuxt-full/src/components/editor/examples/full/extension.ts b/nuxt-full/src/components/editor/examples/full/extension.ts new file mode 100644 index 0000000000..5fc2f60685 --- /dev/null +++ b/nuxt-full/src/components/editor/examples/full/extension.ts @@ -0,0 +1,34 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineImageUploadHandler } from 'prosekit/extensions/image' +import { defineMath } from 'prosekit/extensions/math' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' +import { sampleUploader } from '../../sample/sample-uploader' +import { defineCodeBlockView } from '../../ui/code-block-view' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + defineMention(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + defineCodeBlockShiki(), + defineHorizontalRule(), + defineCodeBlockView(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/nuxt-full/src/components/editor/examples/full/index.ts b/nuxt-full/src/components/editor/examples/full/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/nuxt-full/src/components/editor/examples/full/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/nuxt-full/src/components/editor/sample/katex.ts b/nuxt-full/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/nuxt-full/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/nuxt-full/src/components/editor/sample/sample-doc-full.ts b/nuxt-full/src/components/editor/sample/sample-doc-full.ts new file mode 100644 index 0000000000..13e49b634d --- /dev/null +++ b/nuxt-full/src/components/editor/sample/sample-doc-full.ts @@ -0,0 +1,442 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'The editor that thinks like you' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', + }, + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'writing without barriers', + }, + { type: 'text', text: '.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Text that shines.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Make your words ' }, + { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, + { type: 'text', text: ', or ' }, + { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, + { type: 'text', text: '. Add ' }, + { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, + { type: 'text', text: ' that stands out. Create ' }, + { + type: 'text', + marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], + text: 'links', + }, + { type: 'text', text: ' that connect.' }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Select any text to format it. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '@' }, + { type: 'text', text: ' to mention ' }, + { + type: 'mention', + attrs: { id: '39', value: '@someone', kind: 'user' }, + }, + { type: 'text', text: ' or ' }, + { type: 'text', marks: [{ type: 'code' }], text: '#' }, + { type: 'text', text: ' for ' }, + { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, + { type: 'text', text: '. Press ' }, + { type: 'text', marks: [{ type: 'code' }], text: '/' }, + { type: 'text', text: " and discover what's possible." }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Lists that organize.' }], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Bullet points that guide thoughts' }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Nested lists for complex ideas' }], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sub-points flow naturally' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Tasks that focus' }], + }, + { + type: 'list', + attrs: { kind: 'task', order: null, checked: true, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Done feels good' }], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Todo drives action' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Numbered steps' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sequential thinking' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Clear progress' }], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Code that inspires.' }], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Images that captivate.' }], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/season/320x240/107', + }, + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the handle in the bottom right corner to resize.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Tables that structure.' }], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'Feature', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'How to use', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Format text' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Select and choose' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Perfect styling' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Add mentions' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Type @ and name' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Connected ideas' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Insert anything' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Press / for menu' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Endless possibilities' }], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Math that renders.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Inline math like ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' appears within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Quotes that inspire.' }], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: '"This is not just an editor. This is how writing should feel."', + }, + ], + }, + ], + }, + { type: 'horizontalRule' }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Start typing. Everything else just flows.' }, + ], + }, + ], +} diff --git a/nuxt-full/src/components/editor/sample/sample-tag-data.ts b/nuxt-full/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/nuxt-full/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/nuxt-full/src/components/editor/sample/sample-uploader.ts b/nuxt-full/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/nuxt-full/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/nuxt-full/src/components/editor/sample/sample-user-data.ts b/nuxt-full/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/nuxt-full/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/nuxt-full/src/components/editor/ui/block-handle/block-handle.vue b/nuxt-full/src/components/editor/ui/block-handle/block-handle.vue new file mode 100644 index 0000000000..ba06a1416a --- /dev/null +++ b/nuxt-full/src/components/editor/ui/block-handle/block-handle.vue @@ -0,0 +1,39 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/block-handle/index.ts b/nuxt-full/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..2c33eb5726 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.vue' diff --git a/nuxt-full/src/components/editor/ui/button/button.vue b/nuxt-full/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/button/index.ts b/nuxt-full/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/nuxt-full/src/components/editor/ui/code-block-view/code-block-view.vue b/nuxt-full/src/components/editor/ui/code-block-view/code-block-view.vue new file mode 100644 index 0000000000..e04ea8792e --- /dev/null +++ b/nuxt-full/src/components/editor/ui/code-block-view/code-block-view.vue @@ -0,0 +1,41 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/code-block-view/index.ts b/nuxt-full/src/components/editor/ui/code-block-view/index.ts new file mode 100644 index 0000000000..b7beb100de --- /dev/null +++ b/nuxt-full/src/components/editor/ui/code-block-view/index.ts @@ -0,0 +1,12 @@ +import type { Extension } from 'prosekit/core' +import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' + +import CodeBlockView from './code-block-view.vue' + +export function defineCodeBlockView(): Extension { + return defineVueNodeView({ + name: 'codeBlock', + contentAs: 'code', + component: CodeBlockView as VueNodeViewComponent, + }) +} diff --git a/nuxt-full/src/components/editor/ui/drop-indicator/drop-indicator.vue b/nuxt-full/src/components/editor/ui/drop-indicator/drop-indicator.vue new file mode 100644 index 0000000000..cac51a8629 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/drop-indicator/drop-indicator.vue @@ -0,0 +1,7 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/drop-indicator/index.ts b/nuxt-full/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..b455b1217b --- /dev/null +++ b/nuxt-full/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator.vue' diff --git a/nuxt-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/nuxt-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/image-upload-popover/index.ts b/nuxt-full/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/nuxt-full/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/nuxt-full/src/components/editor/ui/image-view/image-view.vue b/nuxt-full/src/components/editor/ui/image-view/image-view.vue new file mode 100644 index 0000000000..a8beb8acd2 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/image-view/image-view.vue @@ -0,0 +1,97 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/image-view/index.ts b/nuxt-full/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..960e2c64d6 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,11 @@ +import type { Extension } from 'prosekit/core' +import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' + +import ImageView from './image-view.vue' + +export function defineImageView(): Extension { + return defineVueNodeView({ + name: 'image', + component: ImageView as VueNodeViewComponent, + }) +} diff --git a/nuxt-full/src/components/editor/ui/inline-menu/index.ts b/nuxt-full/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8c72e460c8 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.vue' diff --git a/nuxt-full/src/components/editor/ui/inline-menu/inline-menu.vue b/nuxt-full/src/components/editor/ui/inline-menu/inline-menu.vue new file mode 100644 index 0000000000..cacb76b189 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/inline-menu/inline-menu.vue @@ -0,0 +1,219 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/slash-menu/index.ts b/nuxt-full/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..32d71d61f5 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu.vue' diff --git a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue new file mode 100644 index 0000000000..50fc5468fb --- /dev/null +++ b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue @@ -0,0 +1,11 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-item.vue b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-item.vue new file mode 100644 index 0000000000..2d99363b45 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu-item.vue @@ -0,0 +1,24 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/slash-menu/slash-menu.vue b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu.vue new file mode 100644 index 0000000000..87090511e3 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/slash-menu/slash-menu.vue @@ -0,0 +1,106 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/table-handle/index.ts b/nuxt-full/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..0132b96b36 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle.vue' diff --git a/nuxt-full/src/components/editor/ui/table-handle/table-handle.vue b/nuxt-full/src/components/editor/ui/table-handle/table-handle.vue new file mode 100644 index 0000000000..a9921a8f37 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/table-handle/table-handle.vue @@ -0,0 +1,204 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/tag-menu/index.ts b/nuxt-full/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..6cb07b1d1c --- /dev/null +++ b/nuxt-full/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu.vue' diff --git a/nuxt-full/src/components/editor/ui/tag-menu/tag-menu.vue b/nuxt-full/src/components/editor/ui/tag-menu/tag-menu.vue new file mode 100644 index 0000000000..a8928c53a9 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/tag-menu/tag-menu.vue @@ -0,0 +1,59 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/toolbar/index.ts b/nuxt-full/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/nuxt-full/src/components/editor/ui/toolbar/toolbar.vue b/nuxt-full/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/nuxt-full/src/components/editor/ui/user-menu/index.ts b/nuxt-full/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..29fde1b0b4 --- /dev/null +++ b/nuxt-full/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu.vue' diff --git a/nuxt-full/src/components/editor/ui/user-menu/user-menu.vue b/nuxt-full/src/components/editor/ui/user-menu/user-menu.vue new file mode 100644 index 0000000000..60b4c3131c --- /dev/null +++ b/nuxt-full/src/components/editor/ui/user-menu/user-menu.vue @@ -0,0 +1,74 @@ + + + diff --git a/nuxt-full/src/editor.vue b/nuxt-full/src/editor.vue new file mode 100644 index 0000000000..560ed9299f --- /dev/null +++ b/nuxt-full/src/editor.vue @@ -0,0 +1,7 @@ + + + diff --git a/nuxt-full/tsconfig.json b/nuxt-full/tsconfig.json new file mode 100644 index 0000000000..a746f2a70c --- /dev/null +++ b/nuxt-full/tsconfig.json @@ -0,0 +1,4 @@ +{ + // https://nuxt.com/docs/guide/concepts/typescript + "extends": "./.nuxt/tsconfig.json" +} diff --git a/preact-block-handle/.gitignore b/preact-block-handle/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-block-handle/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-block-handle/README.md b/preact-block-handle/README.md new file mode 100644 index 0000000000..8b756b7b1f --- /dev/null +++ b/preact-block-handle/README.md @@ -0,0 +1,15 @@ +# preact-block-handle + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-block-handle) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-block-handle) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-block-handle preact-block-handle +cd preact-block-handle +npm install +npm run dev +``` diff --git a/preact-block-handle/index.html b/preact-block-handle/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-block-handle/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-block-handle/package.json b/preact-block-handle/package.json new file mode 100644 index 0000000000..e4754d7c64 --- /dev/null +++ b/preact-block-handle/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-block-handle", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-block-handle/src/App.tsx b/preact-block-handle/src/App.tsx new file mode 100644 index 0000000000..2cb5b6bb8d --- /dev/null +++ b/preact-block-handle/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/block-handle' + +export default function App() { + return +} diff --git a/preact-block-handle/src/app.css b/preact-block-handle/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-block-handle/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-block-handle/src/components/editor/examples/block-handle/editor.tsx b/preact-block-handle/src/components/editor/examples/block-handle/editor.tsx new file mode 100644 index 0000000000..377510c773 --- /dev/null +++ b/preact-block-handle/src/components/editor/examples/block-handle/editor.tsx @@ -0,0 +1,39 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-block-handle' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/preact-block-handle/src/components/editor/examples/block-handle/extension.ts b/preact-block-handle/src/components/editor/examples/block-handle/extension.ts new file mode 100644 index 0000000000..2c6a5383ad --- /dev/null +++ b/preact-block-handle/src/components/editor/examples/block-handle/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union([defineBasicExtension(), defineCodeBlockView()]) +} + +export type EditorExtension = ReturnType diff --git a/preact-block-handle/src/components/editor/examples/block-handle/index.ts b/preact-block-handle/src/components/editor/examples/block-handle/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-block-handle/src/components/editor/examples/block-handle/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/preact-block-handle/src/components/editor/sample/sample-doc-block-handle.ts new file mode 100644 index 0000000000..3c6ccdc203 --- /dev/null +++ b/preact-block-handle/src/components/editor/sample/sample-doc-block-handle.ts @@ -0,0 +1,323 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Drag and Drop Demo', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Getting Started', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This paragraph can be moved above or below other blocks.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Different Block Types', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'You can drag paragraphs, headings, lists, code blocks, and more.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Lists Work Too', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This entire list can be dragged', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Individual list items stay together', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try moving this list around', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Ordered lists also support dragging', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The numbering updates automatically', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag this list to see it in action', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Even code blocks can be moved:', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: 'javascript', + }, + content: [ + { + type: 'text', + text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Nested Content', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This blockquote can be moved as a single unit.', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested blockquotes move together with their parent.', + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Try It Yourself', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Practice by moving this paragraph to the top of the document.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Or drag this one to between the headings above.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The drag handles make it easy to reorganize your content exactly how you want it.', + }, + ], + }, + ], +} diff --git a/preact-block-handle/src/components/editor/ui/block-handle/block-handle.tsx b/preact-block-handle/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..8f5fe62e40 --- /dev/null +++ b/preact-block-handle/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,31 @@ +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/preact/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/preact-block-handle/src/components/editor/ui/block-handle/index.ts b/preact-block-handle/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/preact-block-handle/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/preact-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx b/preact-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..59e33d3ded --- /dev/null +++ b/preact-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,42 @@ +import type { JSX } from 'preact' +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { PreactNodeViewProps } from 'prosekit/preact' + +export default function CodeBlockView(props: PreactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language || '' + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + const handleChange = (event: JSX.TargetedEvent) => { + setLanguage(event.currentTarget.value) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/preact-block-handle/src/components/editor/ui/code-block-view/index.ts b/preact-block-handle/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..247f963d7e
--- /dev/null
+++ b/preact-block-handle/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  definePreactNodeView,
+  type PreactNodeViewComponent,
+} from 'prosekit/preact'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return definePreactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies PreactNodeViewComponent,
+  })
+}
diff --git a/preact-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/preact-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
new file mode 100644
index 0000000000..6ace546a12
--- /dev/null
+++ b/preact-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
@@ -0,0 +1,5 @@
+import { DropIndicator as BaseDropIndicator } from 'prosekit/preact/drop-indicator'
+
+export default function DropIndicator() {
+  return 
+}
diff --git a/preact-block-handle/src/components/editor/ui/drop-indicator/index.ts b/preact-block-handle/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..f8fb7139c4
--- /dev/null
+++ b/preact-block-handle/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator'
diff --git a/preact-block-handle/src/main.tsx b/preact-block-handle/src/main.tsx
new file mode 100644
index 0000000000..9452b5673a
--- /dev/null
+++ b/preact-block-handle/src/main.tsx
@@ -0,0 +1,5 @@
+import './app.css'
+import { render } from 'preact'
+import App from './App.tsx'
+
+render(, document.getElementById('app')!)
diff --git a/preact-block-handle/tsconfig.app.json b/preact-block-handle/tsconfig.app.json
new file mode 100644
index 0000000000..3fe3ab979d
--- /dev/null
+++ b/preact-block-handle/tsconfig.app.json
@@ -0,0 +1,33 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "target": "ES2022",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "types": ["vite/client"],
+    "skipLibCheck": true,
+    "paths": {
+      "react": ["./node_modules/preact/compat/"],
+      "react-dom": ["./node_modules/preact/compat/"]
+    },
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+    "jsx": "react-jsx",
+    "jsxImportSource": "preact",
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["src"]
+}
diff --git a/preact-block-handle/tsconfig.json b/preact-block-handle/tsconfig.json
new file mode 100644
index 0000000000..1ffef600d9
--- /dev/null
+++ b/preact-block-handle/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "files": [],
+  "references": [
+    { "path": "./tsconfig.app.json" },
+    { "path": "./tsconfig.node.json" }
+  ]
+}
diff --git a/preact-block-handle/tsconfig.node.json b/preact-block-handle/tsconfig.node.json
new file mode 100644
index 0000000000..8a67f62f4c
--- /dev/null
+++ b/preact-block-handle/tsconfig.node.json
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "target": "ES2023",
+    "lib": ["ES2023"],
+    "module": "ESNext",
+    "types": ["node"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/preact-block-handle/vite.config.ts b/preact-block-handle/vite.config.ts
new file mode 100644
index 0000000000..5e0b3c9e1a
--- /dev/null
+++ b/preact-block-handle/vite.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import preact from '@preact/preset-vite'
+import tailwindcss from '@tailwindcss/vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [preact(), tailwindcss()],
+})
diff --git a/preact-blockquote/.gitignore b/preact-blockquote/.gitignore
new file mode 100644
index 0000000000..5d6225c6df
--- /dev/null
+++ b/preact-blockquote/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+.next
+.svelte-kit
diff --git a/preact-blockquote/README.md b/preact-blockquote/README.md
new file mode 100644
index 0000000000..b6f9eb4248
--- /dev/null
+++ b/preact-blockquote/README.md
@@ -0,0 +1,15 @@
+# preact-blockquote
+
+A [ProseKit](https://prosekit.dev) example.
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-blockquote)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-blockquote)
+
+Run the example locally with:
+
+```bash
+npx degit prosekit/examples/preact-blockquote preact-blockquote
+cd preact-blockquote
+npm install
+npm run dev
+```
diff --git a/preact-blockquote/index.html b/preact-blockquote/index.html
new file mode 100644
index 0000000000..b4f79f2233
--- /dev/null
+++ b/preact-blockquote/index.html
@@ -0,0 +1,12 @@
+
+
+  
+    
+    
+    ProseKit + Preact
+  
+  
+    
+ + + diff --git a/preact-blockquote/package.json b/preact-blockquote/package.json new file mode 100644 index 0000000000..6d369bb665 --- /dev/null +++ b/preact-blockquote/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-blockquote", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-blockquote/src/App.tsx b/preact-blockquote/src/App.tsx new file mode 100644 index 0000000000..3327cfcf2d --- /dev/null +++ b/preact-blockquote/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/blockquote' + +export default function App() { + return +} diff --git a/preact-blockquote/src/app.css b/preact-blockquote/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-blockquote/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-blockquote/src/components/editor/examples/blockquote/editor.tsx b/preact-blockquote/src/components/editor/examples/blockquote/editor.tsx new file mode 100644 index 0000000000..47be0af302 --- /dev/null +++ b/preact-blockquote/src/components/editor/examples/blockquote/editor.tsx @@ -0,0 +1,30 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + return createEditor({ extension: defineExtension() }) + }, []) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-blockquote/src/components/editor/examples/blockquote/extension.ts b/preact-blockquote/src/components/editor/examples/blockquote/extension.ts new file mode 100644 index 0000000000..5292b59e35 --- /dev/null +++ b/preact-blockquote/src/components/editor/examples/blockquote/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBlockquote(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-blockquote/src/components/editor/examples/blockquote/index.ts b/preact-blockquote/src/components/editor/examples/blockquote/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-blockquote/src/components/editor/examples/blockquote/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-blockquote/src/components/editor/ui/button/button.tsx b/preact-blockquote/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-blockquote/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-blockquote/src/components/editor/ui/button/index.ts b/preact-blockquote/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-blockquote/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/preact-blockquote/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-blockquote/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-blockquote/src/components/editor/ui/toolbar/index.ts b/preact-blockquote/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-blockquote/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-blockquote/src/components/editor/ui/toolbar/toolbar.tsx b/preact-blockquote/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-blockquote/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-blockquote/src/main.tsx b/preact-blockquote/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-blockquote/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-blockquote/tsconfig.app.json b/preact-blockquote/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-blockquote/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-blockquote/tsconfig.json b/preact-blockquote/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-blockquote/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-blockquote/tsconfig.node.json b/preact-blockquote/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-blockquote/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-blockquote/vite.config.ts b/preact-blockquote/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-blockquote/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-bold/.gitignore b/preact-bold/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-bold/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-bold/README.md b/preact-bold/README.md new file mode 100644 index 0000000000..923dac0c8e --- /dev/null +++ b/preact-bold/README.md @@ -0,0 +1,15 @@ +# preact-bold + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-bold) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-bold) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-bold preact-bold +cd preact-bold +npm install +npm run dev +``` diff --git a/preact-bold/index.html b/preact-bold/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-bold/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-bold/package.json b/preact-bold/package.json new file mode 100644 index 0000000000..7588aa22c4 --- /dev/null +++ b/preact-bold/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-bold", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-bold/src/App.tsx b/preact-bold/src/App.tsx new file mode 100644 index 0000000000..274955047d --- /dev/null +++ b/preact-bold/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/bold' + +export default function App() { + return +} diff --git a/preact-bold/src/app.css b/preact-bold/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-bold/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-bold/src/components/editor/examples/bold/editor.tsx b/preact-bold/src/components/editor/examples/bold/editor.tsx new file mode 100644 index 0000000000..6e699413f5 --- /dev/null +++ b/preact-bold/src/components/editor/examples/bold/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-bold' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-bold/src/components/editor/examples/bold/extension.ts b/preact-bold/src/components/editor/examples/bold/extension.ts new file mode 100644 index 0000000000..eaa4fba721 --- /dev/null +++ b/preact-bold/src/components/editor/examples/bold/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBold } from 'prosekit/extensions/bold' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBold(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-bold/src/components/editor/examples/bold/index.ts b/preact-bold/src/components/editor/examples/bold/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-bold/src/components/editor/examples/bold/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-bold/src/components/editor/sample/sample-doc-bold.ts b/preact-bold/src/components/editor/sample/sample-doc-bold.ts new file mode 100644 index 0000000000..09ed08daad --- /dev/null +++ b/preact-bold/src/components/editor/sample/sample-doc-bold.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/preact-bold/src/components/editor/ui/button/button.tsx b/preact-bold/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-bold/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-bold/src/components/editor/ui/button/index.ts b/preact-bold/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-bold/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-bold/src/components/editor/ui/image-upload-popover/index.ts b/preact-bold/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-bold/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-bold/src/components/editor/ui/toolbar/index.ts b/preact-bold/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-bold/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-bold/src/components/editor/ui/toolbar/toolbar.tsx b/preact-bold/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-bold/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-bold/src/main.tsx b/preact-bold/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-bold/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-bold/tsconfig.app.json b/preact-bold/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-bold/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-bold/tsconfig.json b/preact-bold/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-bold/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-bold/tsconfig.node.json b/preact-bold/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-bold/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-bold/vite.config.ts b/preact-bold/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-bold/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-change-tracking/.gitignore b/preact-change-tracking/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-change-tracking/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-change-tracking/README.md b/preact-change-tracking/README.md new file mode 100644 index 0000000000..2033d9f90d --- /dev/null +++ b/preact-change-tracking/README.md @@ -0,0 +1,15 @@ +# preact-change-tracking + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-change-tracking) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-change-tracking) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-change-tracking preact-change-tracking +cd preact-change-tracking +npm install +npm run dev +``` diff --git a/preact-change-tracking/index.html b/preact-change-tracking/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-change-tracking/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-change-tracking/package.json b/preact-change-tracking/package.json new file mode 100644 index 0000000000..ae2e5ef052 --- /dev/null +++ b/preact-change-tracking/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-change-tracking", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-change-tracking/src/App.tsx b/preact-change-tracking/src/App.tsx new file mode 100644 index 0000000000..88160e69c9 --- /dev/null +++ b/preact-change-tracking/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/change-tracking' + +export default function App() { + return +} diff --git a/preact-change-tracking/src/app.css b/preact-change-tracking/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-change-tracking/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx b/preact-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx new file mode 100644 index 0000000000..16afd59ecd --- /dev/null +++ b/preact-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx @@ -0,0 +1,30 @@ +import { useMemo } from 'preact/hooks' +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, union } from 'prosekit/core' +import { defineCommitViewer, type Commit } from 'prosekit/extensions/commit' +import { defineReadonly } from 'prosekit/extensions/readonly' +import { ProseKit } from 'prosekit/preact' + +export default function EditorDiff(props: { commit: Commit }) { + const editor = useMemo(() => { + const extension = union( + defineBasicExtension(), + defineReadonly(), + defineCommitViewer(props.commit), + ) + return createEditor({ extension }) + }, [props.commit]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx b/preact-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx new file mode 100644 index 0000000000..cfe4253b0b --- /dev/null +++ b/preact-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, union, type NodeJSON } from 'prosekit/core' +import { + defineCommitRecorder, + type CommitRecorder, +} from 'prosekit/extensions/commit' +import { ProseKit } from 'prosekit/preact' + +export default function EditorMain(props: { + commitRecorder: CommitRecorder + initialContent?: NodeJSON +}) { + const editor = useMemo(() => { + const extension = union( + defineBasicExtension(), + defineCommitRecorder(props.commitRecorder), + ) + return createEditor({ extension, defaultContent: props.initialContent }) + }, [props.commitRecorder, props.initialContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-change-tracking/src/components/editor/examples/change-tracking/editor.tsx b/preact-change-tracking/src/components/editor/examples/change-tracking/editor.tsx new file mode 100644 index 0000000000..cdb9a02d22 --- /dev/null +++ b/preact-change-tracking/src/components/editor/examples/change-tracking/editor.tsx @@ -0,0 +1,78 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useCallback, useMemo, useState } from 'preact/hooks' +import type { NodeJSON } from 'prosekit/core' +import { CommitRecorder, type Commit } from 'prosekit/extensions/commit' + +import EditorDiff from './editor-diff' +import EditorMain from './editor-main' + +export default function Editor() { + const [commits, setCommits] = useState< + { id: string; date: Date; commit: Commit }[] + >([]) + const [key, setKey] = useState(0) + const [initialContent, setInitialContent] = useState() + const commitRecorder = useMemo(() => new CommitRecorder(), []) + + const handleCommit = useCallback(() => { + const commit = commitRecorder.commit() + if (!commit) return + const id = Math.random().toString(36).slice(2, 9) + setCommits((existing) => [{ id, date: new Date(), commit }, ...existing]) + }, [commitRecorder]) + + const handleRestore = useCallback( + (id: string) => { + const index = commits.findIndex((commit) => commit.id === id) + const commit = commits[index] + if (index === -1 || !commit) return + const doc = commit.commit.doc + setInitialContent(doc) + setCommits((commits) => commits.slice(index)) + setKey((key) => key + 1) + }, + [commits], + ) + + return ( +
+
+
+ +
+ +
+
+ {commits.map((commit) => ( +
+
+ +
+
+ + {commit.date.toLocaleTimeString()} + + +
+
+ ))} +
+
+ ) +} diff --git a/preact-change-tracking/src/components/editor/examples/change-tracking/index.ts b/preact-change-tracking/src/components/editor/examples/change-tracking/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-change-tracking/src/components/editor/examples/change-tracking/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-change-tracking/src/main.tsx b/preact-change-tracking/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-change-tracking/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-change-tracking/tsconfig.app.json b/preact-change-tracking/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-change-tracking/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-change-tracking/tsconfig.json b/preact-change-tracking/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-change-tracking/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-change-tracking/tsconfig.node.json b/preact-change-tracking/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-change-tracking/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-change-tracking/vite.config.ts b/preact-change-tracking/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-change-tracking/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-code-block-themes/.gitignore b/preact-code-block-themes/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-code-block-themes/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-code-block-themes/README.md b/preact-code-block-themes/README.md new file mode 100644 index 0000000000..5c156daad1 --- /dev/null +++ b/preact-code-block-themes/README.md @@ -0,0 +1,15 @@ +# preact-code-block-themes + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-code-block-themes) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-code-block-themes) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-code-block-themes preact-code-block-themes +cd preact-code-block-themes +npm install +npm run dev +``` diff --git a/preact-code-block-themes/index.html b/preact-code-block-themes/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-code-block-themes/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-code-block-themes/package.json b/preact-code-block-themes/package.json new file mode 100644 index 0000000000..f85fb96f98 --- /dev/null +++ b/preact-code-block-themes/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-code-block-themes", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-code-block-themes/src/App.tsx b/preact-code-block-themes/src/App.tsx new file mode 100644 index 0000000000..9b93464b4e --- /dev/null +++ b/preact-code-block-themes/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code-block-themes' + +export default function App() { + return +} diff --git a/preact-code-block-themes/src/app.css b/preact-code-block-themes/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-code-block-themes/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx b/preact-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx new file mode 100644 index 0000000000..deaadc1187 --- /dev/null +++ b/preact-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-code-block' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/preact-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts new file mode 100644 index 0000000000..b5686b8c04 --- /dev/null +++ b/preact-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union(defineBasicExtension(), defineCodeBlockView()) +} + +export type EditorExtension = ReturnType diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/preact-code-block-themes/src/components/editor/examples/code-block-themes/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-code-block-themes/src/components/editor/examples/code-block-themes/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx b/preact-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx new file mode 100644 index 0000000000..c1f2729eea --- /dev/null +++ b/preact-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx @@ -0,0 +1,38 @@ +import type { JSX } from 'preact' +import { useMemo, useState } from 'preact/hooks' +import { + defineCodeBlockShiki, + shikiBundledThemesInfo, + type ShikiBundledTheme, +} from 'prosekit/extensions/code-block' +import { useExtension } from 'prosekit/preact' + +export function ThemeSelector() { + const [theme, setTheme] = useState('github-dark') + const extension = useMemo(() => { + return defineCodeBlockShiki({ themes: [theme as ShikiBundledTheme] }) + }, [theme]) + useExtension(extension) + + const handleChange = (event: JSX.TargetedEvent) => { + setTheme(event.currentTarget.value) + } + + return ( + <> + + + + ) +} diff --git a/preact-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx b/preact-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx new file mode 100644 index 0000000000..66ebec1e56 --- /dev/null +++ b/preact-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx @@ -0,0 +1,9 @@ +import { ThemeSelector } from './theme-selector' + +export default function Toolbar() { + return ( +
+ +
+ ) +} diff --git a/preact-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/preact-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/preact-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/preact-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx b/preact-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..59e33d3ded --- /dev/null +++ b/preact-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,42 @@ +import type { JSX } from 'preact' +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { PreactNodeViewProps } from 'prosekit/preact' + +export default function CodeBlockView(props: PreactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language || '' + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + const handleChange = (event: JSX.TargetedEvent) => { + setLanguage(event.currentTarget.value) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/preact-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/preact-code-block-themes/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..247f963d7e
--- /dev/null
+++ b/preact-code-block-themes/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  definePreactNodeView,
+  type PreactNodeViewComponent,
+} from 'prosekit/preact'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return definePreactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies PreactNodeViewComponent,
+  })
+}
diff --git a/preact-code-block-themes/src/main.tsx b/preact-code-block-themes/src/main.tsx
new file mode 100644
index 0000000000..9452b5673a
--- /dev/null
+++ b/preact-code-block-themes/src/main.tsx
@@ -0,0 +1,5 @@
+import './app.css'
+import { render } from 'preact'
+import App from './App.tsx'
+
+render(, document.getElementById('app')!)
diff --git a/preact-code-block-themes/tsconfig.app.json b/preact-code-block-themes/tsconfig.app.json
new file mode 100644
index 0000000000..3fe3ab979d
--- /dev/null
+++ b/preact-code-block-themes/tsconfig.app.json
@@ -0,0 +1,33 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "target": "ES2022",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "types": ["vite/client"],
+    "skipLibCheck": true,
+    "paths": {
+      "react": ["./node_modules/preact/compat/"],
+      "react-dom": ["./node_modules/preact/compat/"]
+    },
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+    "jsx": "react-jsx",
+    "jsxImportSource": "preact",
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["src"]
+}
diff --git a/preact-code-block-themes/tsconfig.json b/preact-code-block-themes/tsconfig.json
new file mode 100644
index 0000000000..1ffef600d9
--- /dev/null
+++ b/preact-code-block-themes/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "files": [],
+  "references": [
+    { "path": "./tsconfig.app.json" },
+    { "path": "./tsconfig.node.json" }
+  ]
+}
diff --git a/preact-code-block-themes/tsconfig.node.json b/preact-code-block-themes/tsconfig.node.json
new file mode 100644
index 0000000000..8a67f62f4c
--- /dev/null
+++ b/preact-code-block-themes/tsconfig.node.json
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "target": "ES2023",
+    "lib": ["ES2023"],
+    "module": "ESNext",
+    "types": ["node"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/preact-code-block-themes/vite.config.ts b/preact-code-block-themes/vite.config.ts
new file mode 100644
index 0000000000..5e0b3c9e1a
--- /dev/null
+++ b/preact-code-block-themes/vite.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import preact from '@preact/preset-vite'
+import tailwindcss from '@tailwindcss/vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [preact(), tailwindcss()],
+})
diff --git a/preact-code-block/.gitignore b/preact-code-block/.gitignore
new file mode 100644
index 0000000000..5d6225c6df
--- /dev/null
+++ b/preact-code-block/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+.next
+.svelte-kit
diff --git a/preact-code-block/README.md b/preact-code-block/README.md
new file mode 100644
index 0000000000..2b711d1606
--- /dev/null
+++ b/preact-code-block/README.md
@@ -0,0 +1,15 @@
+# preact-code-block
+
+A [ProseKit](https://prosekit.dev) example.
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-code-block)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-code-block)
+
+Run the example locally with:
+
+```bash
+npx degit prosekit/examples/preact-code-block preact-code-block
+cd preact-code-block
+npm install
+npm run dev
+```
diff --git a/preact-code-block/index.html b/preact-code-block/index.html
new file mode 100644
index 0000000000..b4f79f2233
--- /dev/null
+++ b/preact-code-block/index.html
@@ -0,0 +1,12 @@
+
+
+  
+    
+    
+    ProseKit + Preact
+  
+  
+    
+ + + diff --git a/preact-code-block/package.json b/preact-code-block/package.json new file mode 100644 index 0000000000..608adce773 --- /dev/null +++ b/preact-code-block/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-code-block", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-code-block/src/App.tsx b/preact-code-block/src/App.tsx new file mode 100644 index 0000000000..961ce70aad --- /dev/null +++ b/preact-code-block/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code-block' + +export default function App() { + return +} diff --git a/preact-code-block/src/app.css b/preact-code-block/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-code-block/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-code-block/src/components/editor/examples/code-block/editor.tsx b/preact-code-block/src/components/editor/examples/code-block/editor.tsx new file mode 100644 index 0000000000..10a3458f9d --- /dev/null +++ b/preact-code-block/src/components/editor/examples/code-block/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-code-block' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-code-block/src/components/editor/examples/code-block/extension.ts b/preact-code-block/src/components/editor/examples/code-block/extension.ts new file mode 100644 index 0000000000..099cacf03b --- /dev/null +++ b/preact-code-block/src/components/editor/examples/code-block/extension.ts @@ -0,0 +1,24 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { + defineCodeBlock, + defineCodeBlockShiki, +} from 'prosekit/extensions/code-block' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCodeBlock(), + defineCodeBlockShiki(), + defineCodeBlockView(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-code-block/src/components/editor/examples/code-block/index.ts b/preact-code-block/src/components/editor/examples/code-block/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-code-block/src/components/editor/examples/code-block/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-code-block/src/components/editor/sample/sample-doc-code-block.ts b/preact-code-block/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/preact-code-block/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/preact-code-block/src/components/editor/ui/button/button.tsx b/preact-code-block/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-code-block/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-code-block/src/components/editor/ui/button/index.ts b/preact-code-block/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-code-block/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx b/preact-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..59e33d3ded --- /dev/null +++ b/preact-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,42 @@ +import type { JSX } from 'preact' +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { PreactNodeViewProps } from 'prosekit/preact' + +export default function CodeBlockView(props: PreactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language || '' + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + const handleChange = (event: JSX.TargetedEvent) => { + setLanguage(event.currentTarget.value) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/preact-code-block/src/components/editor/ui/code-block-view/index.ts b/preact-code-block/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..247f963d7e
--- /dev/null
+++ b/preact-code-block/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  definePreactNodeView,
+  type PreactNodeViewComponent,
+} from 'prosekit/preact'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return definePreactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies PreactNodeViewComponent,
+  })
+}
diff --git a/preact-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
new file mode 100644
index 0000000000..764667a8c0
--- /dev/null
+++ b/preact-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
@@ -0,0 +1,144 @@
+import type { ComponentChild, JSX } from 'preact'
+import { useId, useState } from 'preact/hooks'
+import type { Uploader } from 'prosekit/extensions/file'
+import type { ImageExtension } from 'prosekit/extensions/image'
+import { useEditor } from 'prosekit/preact'
+import {
+  PopoverPopup,
+  PopoverPositioner,
+  PopoverRoot,
+  PopoverTrigger,
+} from 'prosekit/preact/popover'
+import type { OpenChangeEvent } from 'prosekit/web/popover'
+
+import { Button } from '../button'
+
+export default function ImageUploadPopover(props: {
+  uploader: Uploader
+  tooltip: string
+  disabled: boolean
+  children: ComponentChild
+}) {
+  const [open, setOpen] = useState(false)
+  const [url, setUrl] = useState('')
+  const [file, setFile] = useState(null)
+  const ariaId = useId()
+
+  const editor = useEditor()
+
+  const handleFileChange = (
+    event: JSX.TargetedEvent,
+  ) => {
+    const file = event.currentTarget.files?.[0]
+
+    if (file) {
+      setFile(file)
+      setUrl('')
+    } else {
+      setFile(null)
+    }
+  }
+
+  const handleUrlChange = (
+    event: JSX.TargetedEvent,
+  ) => {
+    const url = event.currentTarget.value
+
+    if (url) {
+      setUrl(url)
+      setFile(null)
+    } else {
+      setUrl('')
+    }
+  }
+
+  const deferResetState = () => {
+    setTimeout(() => {
+      setUrl('')
+      setFile(null)
+    }, 300)
+  }
+
+  const handleSubmit = () => {
+    if (url) {
+      editor.commands.insertImage({ src: url })
+    } else if (file) {
+      editor.commands.uploadImage({ file, uploader: props.uploader })
+    }
+    setOpen(false)
+    deferResetState()
+  }
+
+  const handleOpenChange = (event: OpenChangeEvent) => {
+    if (!event.detail) {
+      deferResetState()
+    }
+    setOpen(event.detail)
+  }
+
+  return (
+    
+      
+        
+      
+
+      
+        
+          {file ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? (
+            
+          ) : null}
+
+          {file ? (
+            
+          ) : null}
+        
+      
+    
+  )
+}
diff --git a/preact-code-block/src/components/editor/ui/image-upload-popover/index.ts b/preact-code-block/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..5d49d873ce
--- /dev/null
+++ b/preact-code-block/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/preact-code-block/src/components/editor/ui/toolbar/index.ts b/preact-code-block/src/components/editor/ui/toolbar/index.ts
new file mode 100644
index 0000000000..fdf6741e6a
--- /dev/null
+++ b/preact-code-block/src/components/editor/ui/toolbar/index.ts
@@ -0,0 +1 @@
+export { default as Toolbar } from './toolbar'
diff --git a/preact-code-block/src/components/editor/ui/toolbar/toolbar.tsx b/preact-code-block/src/components/editor/ui/toolbar/toolbar.tsx
new file mode 100644
index 0000000000..746a58435a
--- /dev/null
+++ b/preact-code-block/src/components/editor/ui/toolbar/toolbar.tsx
@@ -0,0 +1,363 @@
+import type { BasicExtension } from 'prosekit/basic'
+import type { Editor } from 'prosekit/core'
+import type { Uploader } from 'prosekit/extensions/file'
+import { useEditorDerivedValue } from 'prosekit/preact'
+
+import { Button } from '../button'
+import { ImageUploadPopover } from '../image-upload-popover'
+
+function getToolbarItems(editor: Editor) {
+  return {
+    undo: editor.commands.undo
+      ? {
+          isActive: false,
+          canExec: editor.commands.undo.canExec(),
+          command: () => editor.commands.undo(),
+        }
+      : undefined,
+    redo: editor.commands.redo
+      ? {
+          isActive: false,
+          canExec: editor.commands.redo.canExec(),
+          command: () => editor.commands.redo(),
+        }
+      : undefined,
+    bold: editor.commands.toggleBold
+      ? {
+          isActive: editor.marks.bold.isActive(),
+          canExec: editor.commands.toggleBold.canExec(),
+          command: () => editor.commands.toggleBold(),
+        }
+      : undefined,
+    italic: editor.commands.toggleItalic
+      ? {
+          isActive: editor.marks.italic.isActive(),
+          canExec: editor.commands.toggleItalic.canExec(),
+          command: () => editor.commands.toggleItalic(),
+        }
+      : undefined,
+    underline: editor.commands.toggleUnderline
+      ? {
+          isActive: editor.marks.underline.isActive(),
+          canExec: editor.commands.toggleUnderline.canExec(),
+          command: () => editor.commands.toggleUnderline(),
+        }
+      : undefined,
+    strike: editor.commands.toggleStrike
+      ? {
+          isActive: editor.marks.strike.isActive(),
+          canExec: editor.commands.toggleStrike.canExec(),
+          command: () => editor.commands.toggleStrike(),
+        }
+      : undefined,
+    code: editor.commands.toggleCode
+      ? {
+          isActive: editor.marks.code.isActive(),
+          canExec: editor.commands.toggleCode.canExec(),
+          command: () => editor.commands.toggleCode(),
+        }
+      : undefined,
+    codeBlock: editor.commands.insertCodeBlock
+      ? {
+          isActive: editor.nodes.codeBlock.isActive(),
+          canExec: editor.commands.insertCodeBlock.canExec({
+            language: 'javascript',
+          }),
+          command: () =>
+            editor.commands.insertCodeBlock({ language: 'javascript' }),
+        }
+      : undefined,
+    heading1: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 1 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 1 }),
+          command: () => editor.commands.toggleHeading({ level: 1 }),
+        }
+      : undefined,
+    heading2: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 2 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 2 }),
+          command: () => editor.commands.toggleHeading({ level: 2 }),
+        }
+      : undefined,
+    heading3: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 3 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 3 }),
+          command: () => editor.commands.toggleHeading({ level: 3 }),
+        }
+      : undefined,
+    horizontalRule: editor.commands.insertHorizontalRule
+      ? {
+          isActive: editor.nodes.horizontalRule.isActive(),
+          canExec: editor.commands.insertHorizontalRule.canExec(),
+          command: () => editor.commands.insertHorizontalRule(),
+        }
+      : undefined,
+    blockquote: editor.commands.toggleBlockquote
+      ? {
+          isActive: editor.nodes.blockquote.isActive(),
+          canExec: editor.commands.toggleBlockquote.canExec(),
+          command: () => editor.commands.toggleBlockquote(),
+        }
+      : undefined,
+    bulletList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'bullet' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }),
+          command: () => editor.commands.toggleList({ kind: 'bullet' }),
+        }
+      : undefined,
+    orderedList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'ordered' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }),
+          command: () => editor.commands.toggleList({ kind: 'ordered' }),
+        }
+      : undefined,
+    taskList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'task' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'task' }),
+          command: () => editor.commands.toggleList({ kind: 'task' }),
+        }
+      : undefined,
+    toggleList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'toggle' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }),
+          command: () => editor.commands.toggleList({ kind: 'toggle' }),
+        }
+      : undefined,
+    indentList: editor.commands.indentList
+      ? {
+          isActive: false,
+          canExec: editor.commands.indentList.canExec(),
+          command: () => editor.commands.indentList(),
+        }
+      : undefined,
+    dedentList: editor.commands.dedentList
+      ? {
+          isActive: false,
+          canExec: editor.commands.dedentList.canExec(),
+          command: () => editor.commands.dedentList(),
+        }
+      : undefined,
+    insertImage: editor.commands.insertImage
+      ? {
+          isActive: false,
+          canExec: editor.commands.insertImage.canExec(),
+        }
+      : undefined,
+  }
+}
+
+export default function Toolbar(props: { uploader?: Uploader }) {
+  const items = useEditorDerivedValue(getToolbarItems)
+
+  return (
+    
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-code-block/src/main.tsx b/preact-code-block/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-code-block/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-code-block/tsconfig.app.json b/preact-code-block/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-code-block/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-code-block/tsconfig.json b/preact-code-block/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-code-block/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-code-block/tsconfig.node.json b/preact-code-block/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-code-block/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-code-block/vite.config.ts b/preact-code-block/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-code-block/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-code/.gitignore b/preact-code/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-code/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-code/README.md b/preact-code/README.md new file mode 100644 index 0000000000..079055fbad --- /dev/null +++ b/preact-code/README.md @@ -0,0 +1,15 @@ +# preact-code + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-code) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-code) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-code preact-code +cd preact-code +npm install +npm run dev +``` diff --git a/preact-code/index.html b/preact-code/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-code/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-code/package.json b/preact-code/package.json new file mode 100644 index 0000000000..4ce228ea74 --- /dev/null +++ b/preact-code/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-code", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-code/src/App.tsx b/preact-code/src/App.tsx new file mode 100644 index 0000000000..f2f5d9a360 --- /dev/null +++ b/preact-code/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code' + +export default function App() { + return +} diff --git a/preact-code/src/app.css b/preact-code/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-code/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-code/src/components/editor/examples/code/editor.tsx b/preact-code/src/components/editor/examples/code/editor.tsx new file mode 100644 index 0000000000..a3b39cd30f --- /dev/null +++ b/preact-code/src/components/editor/examples/code/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-code' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-code/src/components/editor/examples/code/extension.ts b/preact-code/src/components/editor/examples/code/extension.ts new file mode 100644 index 0000000000..e9e273216e --- /dev/null +++ b/preact-code/src/components/editor/examples/code/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCode(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-code/src/components/editor/examples/code/index.ts b/preact-code/src/components/editor/examples/code/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-code/src/components/editor/examples/code/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-code/src/components/editor/sample/sample-doc-code.ts b/preact-code/src/components/editor/sample/sample-doc-code.ts new file mode 100644 index 0000000000..2fdbcee1f3 --- /dev/null +++ b/preact-code/src/components/editor/sample/sample-doc-code.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'This is code', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/preact-code/src/components/editor/ui/button/button.tsx b/preact-code/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-code/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-code/src/components/editor/ui/button/index.ts b/preact-code/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-code/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-code/src/components/editor/ui/image-upload-popover/index.ts b/preact-code/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-code/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-code/src/components/editor/ui/toolbar/index.ts b/preact-code/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-code/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-code/src/components/editor/ui/toolbar/toolbar.tsx b/preact-code/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-code/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-code/src/main.tsx b/preact-code/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-code/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-code/tsconfig.app.json b/preact-code/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-code/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-code/tsconfig.json b/preact-code/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-code/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-code/tsconfig.node.json b/preact-code/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-code/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-code/vite.config.ts b/preact-code/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-code/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-drop-cursor/.gitignore b/preact-drop-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-drop-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-drop-cursor/README.md b/preact-drop-cursor/README.md new file mode 100644 index 0000000000..a0d9f533a0 --- /dev/null +++ b/preact-drop-cursor/README.md @@ -0,0 +1,15 @@ +# preact-drop-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-drop-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-drop-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-drop-cursor preact-drop-cursor +cd preact-drop-cursor +npm install +npm run dev +``` diff --git a/preact-drop-cursor/index.html b/preact-drop-cursor/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-drop-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-drop-cursor/package.json b/preact-drop-cursor/package.json new file mode 100644 index 0000000000..bbece0ba5e --- /dev/null +++ b/preact-drop-cursor/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-drop-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-drop-cursor/src/App.tsx b/preact-drop-cursor/src/App.tsx new file mode 100644 index 0000000000..f66459b286 --- /dev/null +++ b/preact-drop-cursor/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/drop-cursor' + +export default function App() { + return +} diff --git a/preact-drop-cursor/src/app.css b/preact-drop-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-drop-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx b/preact-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx new file mode 100644 index 0000000000..8da7c938f1 --- /dev/null +++ b/preact-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-drop-cursor' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/preact-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts new file mode 100644 index 0000000000..fd79a2c96c --- /dev/null +++ b/preact-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts @@ -0,0 +1,23 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineImage(), + defineDropCursor({ + color: false, + width: 4, + class: 'transition-all bg-blue-500', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/preact-drop-cursor/src/components/editor/examples/drop-cursor/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-drop-cursor/src/components/editor/examples/drop-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/preact-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts new file mode 100644 index 0000000000..22c6b93465 --- /dev/null +++ b/preact-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts @@ -0,0 +1,40 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the images below to see the custom drop cursor.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/320x240/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/green/320x240/40', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blue/320x240/187', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/red/320x240/188', + }, + }, + ], +} diff --git a/preact-drop-cursor/src/main.tsx b/preact-drop-cursor/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-drop-cursor/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-drop-cursor/tsconfig.app.json b/preact-drop-cursor/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-drop-cursor/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-drop-cursor/tsconfig.json b/preact-drop-cursor/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-drop-cursor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-drop-cursor/tsconfig.node.json b/preact-drop-cursor/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-drop-cursor/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-drop-cursor/vite.config.ts b/preact-drop-cursor/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-drop-cursor/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-emoji-rules/.gitignore b/preact-emoji-rules/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-emoji-rules/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-emoji-rules/README.md b/preact-emoji-rules/README.md new file mode 100644 index 0000000000..72ba488c3d --- /dev/null +++ b/preact-emoji-rules/README.md @@ -0,0 +1,15 @@ +# preact-emoji-rules + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-emoji-rules) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-emoji-rules) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-emoji-rules preact-emoji-rules +cd preact-emoji-rules +npm install +npm run dev +``` diff --git a/preact-emoji-rules/index.html b/preact-emoji-rules/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-emoji-rules/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-emoji-rules/package.json b/preact-emoji-rules/package.json new file mode 100644 index 0000000000..ef6efa80d6 --- /dev/null +++ b/preact-emoji-rules/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-emoji-rules", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-emoji-rules/src/App.tsx b/preact-emoji-rules/src/App.tsx new file mode 100644 index 0000000000..1e4ef54fd6 --- /dev/null +++ b/preact-emoji-rules/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/emoji-rules' + +export default function App() { + return +} diff --git a/preact-emoji-rules/src/app.css b/preact-emoji-rules/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-emoji-rules/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx b/preact-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx new file mode 100644 index 0000000000..3b01b9885a --- /dev/null +++ b/preact-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx @@ -0,0 +1,28 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/preact-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts new file mode 100644 index 0000000000..5cac9cbc79 --- /dev/null +++ b/preact-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts @@ -0,0 +1,15 @@ +import { defineEnterRule } from 'prosekit/extensions/enter-rule' + +/** + * Converts the text before the text cursor into an emoji when pressing `Enter`. + */ +export function defineEmojiEnterRule() { + return defineEnterRule({ + regex: /:(apple|banana):$/, + handler: ({ match, from, to, state }) => { + const text = match[1] as 'apple' | 'banana' + const emoji = text === 'apple' ? '🍎' : '🍌' + return state.tr.replaceWith(from, to, state.schema.text(emoji)) + }, + }) +} diff --git a/preact-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/preact-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts new file mode 100644 index 0000000000..bc9bcb8412 --- /dev/null +++ b/preact-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts @@ -0,0 +1,15 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { defineEmojiEnterRule } from './emoji' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineEmojiEnterRule(), + definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/preact-emoji-rules/src/components/editor/examples/emoji-rules/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-emoji-rules/src/components/editor/examples/emoji-rules/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-emoji-rules/src/main.tsx b/preact-emoji-rules/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-emoji-rules/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-emoji-rules/tsconfig.app.json b/preact-emoji-rules/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-emoji-rules/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-emoji-rules/tsconfig.json b/preact-emoji-rules/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-emoji-rules/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-emoji-rules/tsconfig.node.json b/preact-emoji-rules/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-emoji-rules/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-emoji-rules/vite.config.ts b/preact-emoji-rules/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-emoji-rules/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-full/.gitignore b/preact-full/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-full/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-full/README.md b/preact-full/README.md new file mode 100644 index 0000000000..a755515e86 --- /dev/null +++ b/preact-full/README.md @@ -0,0 +1,15 @@ +# preact-full + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-full) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-full) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-full preact-full +cd preact-full +npm install +npm run dev +``` diff --git a/preact-full/index.html b/preact-full/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-full/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-full/package.json b/preact-full/package.json new file mode 100644 index 0000000000..9c84476c04 --- /dev/null +++ b/preact-full/package.json @@ -0,0 +1,26 @@ +{ + "name": "example-preact-full", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-full/src/App.tsx b/preact-full/src/App.tsx new file mode 100644 index 0000000000..c93bd3a429 --- /dev/null +++ b/preact-full/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/full' + +export default function App() { + return +} diff --git a/preact-full/src/app.css b/preact-full/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-full/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-full/src/components/editor/examples/full/editor.tsx b/preact-full/src/components/editor/examples/full/editor.tsx new file mode 100644 index 0000000000..2a2cc247e9 --- /dev/null +++ b/preact-full/src/components/editor/examples/full/editor.tsx @@ -0,0 +1,54 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-full' +import { tags } from '../../sample/sample-tag-data' +import { sampleUploader } from '../../sample/sample-uploader' +import { users } from '../../sample/sample-user-data' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' +import { InlineMenu } from '../../ui/inline-menu' +import { SlashMenu } from '../../ui/slash-menu' +import { TableHandle } from '../../ui/table-handle' +import { TagMenu } from '../../ui/tag-menu' +import { Toolbar } from '../../ui/toolbar' +import { UserMenu } from '../../ui/user-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+ + + + + + + +
+
+
+ ) +} diff --git a/preact-full/src/components/editor/examples/full/extension.ts b/preact-full/src/components/editor/examples/full/extension.ts new file mode 100644 index 0000000000..5fc2f60685 --- /dev/null +++ b/preact-full/src/components/editor/examples/full/extension.ts @@ -0,0 +1,34 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineImageUploadHandler } from 'prosekit/extensions/image' +import { defineMath } from 'prosekit/extensions/math' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' +import { sampleUploader } from '../../sample/sample-uploader' +import { defineCodeBlockView } from '../../ui/code-block-view' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + defineMention(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + defineCodeBlockShiki(), + defineHorizontalRule(), + defineCodeBlockView(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-full/src/components/editor/examples/full/index.ts b/preact-full/src/components/editor/examples/full/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-full/src/components/editor/examples/full/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-full/src/components/editor/sample/katex.ts b/preact-full/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/preact-full/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/preact-full/src/components/editor/sample/sample-doc-full.ts b/preact-full/src/components/editor/sample/sample-doc-full.ts new file mode 100644 index 0000000000..13e49b634d --- /dev/null +++ b/preact-full/src/components/editor/sample/sample-doc-full.ts @@ -0,0 +1,442 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'The editor that thinks like you' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', + }, + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'writing without barriers', + }, + { type: 'text', text: '.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Text that shines.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Make your words ' }, + { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, + { type: 'text', text: ', or ' }, + { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, + { type: 'text', text: '. Add ' }, + { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, + { type: 'text', text: ' that stands out. Create ' }, + { + type: 'text', + marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], + text: 'links', + }, + { type: 'text', text: ' that connect.' }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Select any text to format it. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '@' }, + { type: 'text', text: ' to mention ' }, + { + type: 'mention', + attrs: { id: '39', value: '@someone', kind: 'user' }, + }, + { type: 'text', text: ' or ' }, + { type: 'text', marks: [{ type: 'code' }], text: '#' }, + { type: 'text', text: ' for ' }, + { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, + { type: 'text', text: '. Press ' }, + { type: 'text', marks: [{ type: 'code' }], text: '/' }, + { type: 'text', text: " and discover what's possible." }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Lists that organize.' }], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Bullet points that guide thoughts' }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Nested lists for complex ideas' }], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sub-points flow naturally' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Tasks that focus' }], + }, + { + type: 'list', + attrs: { kind: 'task', order: null, checked: true, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Done feels good' }], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Todo drives action' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Numbered steps' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sequential thinking' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Clear progress' }], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Code that inspires.' }], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Images that captivate.' }], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/season/320x240/107', + }, + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the handle in the bottom right corner to resize.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Tables that structure.' }], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'Feature', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'How to use', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Format text' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Select and choose' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Perfect styling' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Add mentions' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Type @ and name' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Connected ideas' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Insert anything' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Press / for menu' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Endless possibilities' }], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Math that renders.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Inline math like ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' appears within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Quotes that inspire.' }], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: '"This is not just an editor. This is how writing should feel."', + }, + ], + }, + ], + }, + { type: 'horizontalRule' }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Start typing. Everything else just flows.' }, + ], + }, + ], +} diff --git a/preact-full/src/components/editor/sample/sample-tag-data.ts b/preact-full/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/preact-full/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/preact-full/src/components/editor/sample/sample-uploader.ts b/preact-full/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/preact-full/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/preact-full/src/components/editor/sample/sample-user-data.ts b/preact-full/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/preact-full/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/preact-full/src/components/editor/ui/block-handle/block-handle.tsx b/preact-full/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..8f5fe62e40 --- /dev/null +++ b/preact-full/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,31 @@ +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/preact/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/preact-full/src/components/editor/ui/block-handle/index.ts b/preact-full/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/preact-full/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/preact-full/src/components/editor/ui/button/button.tsx b/preact-full/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-full/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-full/src/components/editor/ui/button/index.ts b/preact-full/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-full/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-full/src/components/editor/ui/code-block-view/code-block-view.tsx b/preact-full/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..59e33d3ded --- /dev/null +++ b/preact-full/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,42 @@ +import type { JSX } from 'preact' +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { PreactNodeViewProps } from 'prosekit/preact' + +export default function CodeBlockView(props: PreactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language || '' + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + const handleChange = (event: JSX.TargetedEvent) => { + setLanguage(event.currentTarget.value) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/preact-full/src/components/editor/ui/code-block-view/index.ts b/preact-full/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..247f963d7e
--- /dev/null
+++ b/preact-full/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  definePreactNodeView,
+  type PreactNodeViewComponent,
+} from 'prosekit/preact'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return definePreactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies PreactNodeViewComponent,
+  })
+}
diff --git a/preact-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/preact-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
new file mode 100644
index 0000000000..6ace546a12
--- /dev/null
+++ b/preact-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
@@ -0,0 +1,5 @@
+import { DropIndicator as BaseDropIndicator } from 'prosekit/preact/drop-indicator'
+
+export default function DropIndicator() {
+  return 
+}
diff --git a/preact-full/src/components/editor/ui/drop-indicator/index.ts b/preact-full/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..f8fb7139c4
--- /dev/null
+++ b/preact-full/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator'
diff --git a/preact-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
new file mode 100644
index 0000000000..764667a8c0
--- /dev/null
+++ b/preact-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
@@ -0,0 +1,144 @@
+import type { ComponentChild, JSX } from 'preact'
+import { useId, useState } from 'preact/hooks'
+import type { Uploader } from 'prosekit/extensions/file'
+import type { ImageExtension } from 'prosekit/extensions/image'
+import { useEditor } from 'prosekit/preact'
+import {
+  PopoverPopup,
+  PopoverPositioner,
+  PopoverRoot,
+  PopoverTrigger,
+} from 'prosekit/preact/popover'
+import type { OpenChangeEvent } from 'prosekit/web/popover'
+
+import { Button } from '../button'
+
+export default function ImageUploadPopover(props: {
+  uploader: Uploader
+  tooltip: string
+  disabled: boolean
+  children: ComponentChild
+}) {
+  const [open, setOpen] = useState(false)
+  const [url, setUrl] = useState('')
+  const [file, setFile] = useState(null)
+  const ariaId = useId()
+
+  const editor = useEditor()
+
+  const handleFileChange = (
+    event: JSX.TargetedEvent,
+  ) => {
+    const file = event.currentTarget.files?.[0]
+
+    if (file) {
+      setFile(file)
+      setUrl('')
+    } else {
+      setFile(null)
+    }
+  }
+
+  const handleUrlChange = (
+    event: JSX.TargetedEvent,
+  ) => {
+    const url = event.currentTarget.value
+
+    if (url) {
+      setUrl(url)
+      setFile(null)
+    } else {
+      setUrl('')
+    }
+  }
+
+  const deferResetState = () => {
+    setTimeout(() => {
+      setUrl('')
+      setFile(null)
+    }, 300)
+  }
+
+  const handleSubmit = () => {
+    if (url) {
+      editor.commands.insertImage({ src: url })
+    } else if (file) {
+      editor.commands.uploadImage({ file, uploader: props.uploader })
+    }
+    setOpen(false)
+    deferResetState()
+  }
+
+  const handleOpenChange = (event: OpenChangeEvent) => {
+    if (!event.detail) {
+      deferResetState()
+    }
+    setOpen(event.detail)
+  }
+
+  return (
+    
+      
+        
+      
+
+      
+        
+          {file ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? (
+            
+          ) : null}
+
+          {file ? (
+            
+          ) : null}
+        
+      
+    
+  )
+}
diff --git a/preact-full/src/components/editor/ui/image-upload-popover/index.ts b/preact-full/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..5d49d873ce
--- /dev/null
+++ b/preact-full/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/preact-full/src/components/editor/ui/image-view/image-view.tsx b/preact-full/src/components/editor/ui/image-view/image-view.tsx
new file mode 100644
index 0000000000..1b83843d1a
--- /dev/null
+++ b/preact-full/src/components/editor/ui/image-view/image-view.tsx
@@ -0,0 +1,95 @@
+import type { JSX } from 'preact'
+import { useEffect, useState } from 'preact/hooks'
+import { UploadTask } from 'prosekit/extensions/file'
+import type { ImageAttrs } from 'prosekit/extensions/image'
+import type { PreactNodeViewProps } from 'prosekit/preact'
+import { ResizableHandle, ResizableRoot } from 'prosekit/preact/resizable'
+
+export default function ImageView(props: PreactNodeViewProps) {
+  const attrs = props.node.attrs as ImageAttrs
+  const url = attrs.src || ''
+  const uploading = url.startsWith('blob:')
+
+  const [aspectRatio, setAspectRatio] = useState()
+  const [error, setError] = useState()
+  const [progress, setProgress] = useState(0)
+
+  useEffect(() => {
+    if (!uploading) return
+
+    const uploadTask = UploadTask.get(url)
+    if (!uploadTask) return
+
+    let canceled = false
+
+    uploadTask.finished.catch((error) => {
+      if (canceled) return
+      setError(String(error))
+    })
+    const unsubscribeProgress = uploadTask.subscribeProgress(
+      ({ loaded, total }) => {
+        if (canceled) return
+        setProgress(total ? loaded / total : 0)
+      },
+    )
+
+    return () => {
+      canceled = true
+      unsubscribeProgress()
+    }
+  }, [url, uploading])
+
+  const handleImageLoad = (
+    event: JSX.TargetedEvent,
+  ) => {
+    const img = event.currentTarget
+    const { naturalWidth, naturalHeight } = img
+    const ratio = naturalWidth / naturalHeight
+    if (ratio && Number.isFinite(ratio)) {
+      setAspectRatio(ratio)
+    }
+    if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) {
+      props.setAttrs({ width: naturalWidth, height: naturalHeight })
+    }
+  }
+
+  return (
+     props.setAttrs(event.detail)}
+      data-selected={props.selected ? '' : undefined}
+      className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid"
+    >
+      {url && !error && (
+        upload preview
+      )}
+      {uploading && !error && (
+        
+
+
{Math.round(progress * 100)}%
+
+ )} + {error && ( +
+
+
+ Failed to upload image +
+
+ )} + +
+
+
+ ) +} diff --git a/preact-full/src/components/editor/ui/image-view/index.ts b/preact-full/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..2b8200267d --- /dev/null +++ b/preact-full/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + definePreactNodeView, + type PreactNodeViewComponent, +} from 'prosekit/preact' + +import ImageView from './image-view' + +export function defineImageView(): Extension { + return definePreactNodeView({ + name: 'image', + component: ImageView satisfies PreactNodeViewComponent, + }) +} diff --git a/preact-full/src/components/editor/ui/inline-menu/index.ts b/preact-full/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/preact-full/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/preact-full/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-full/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..a014b74f57 --- /dev/null +++ b/preact-full/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +import type { JSX } from 'preact' +import { useState } from 'preact/hooks' +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/preact' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/preact/inline-popover' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + const handleSubmit = ( + event: JSX.TargetedEvent, + ) => { + event.preventDefault() + const href = event.currentTarget.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
+ +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/preact-full/src/components/editor/ui/slash-menu/index.ts b/preact-full/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/preact-full/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/preact-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/preact-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..bedf7d7ebb --- /dev/null +++ b/preact-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,9 @@ +import { AutocompleteEmpty } from 'prosekit/preact/autocomplete' + +export default function SlashMenuEmpty() { + return ( + + No results + + ) +} diff --git a/preact-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/preact-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..1bb81f797d --- /dev/null +++ b/preact-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,21 @@ +import { AutocompleteItem } from 'prosekit/preact/autocomplete' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}) { + return ( + + {props.label} + {props.kbd && ( + + {props.kbd} + + )} + + ) +} diff --git a/preact-full/src/components/editor/ui/slash-menu/slash-menu.tsx b/preact-full/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..092327c28e --- /dev/null +++ b/preact-full/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,100 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/preact' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/preact/autocomplete' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor.commands.setParagraph()} + /> + + editor.commands.setHeading({ level: 1 })} + /> + + editor.commands.setHeading({ level: 2 })} + /> + + editor.commands.setHeading({ level: 3 })} + /> + + editor.commands.wrapInList({ kind: 'bullet' })} + /> + + editor.commands.wrapInList({ kind: 'ordered' })} + /> + + editor.commands.wrapInList({ kind: 'task' })} + /> + + editor.commands.wrapInList({ kind: 'toggle' })} + /> + + editor.commands.setBlockquote()} + /> + + editor.commands.insertTable({ row: 3, col: 3 })} + /> + + editor.commands.insertHorizontalRule()} + /> + + editor.commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/preact-full/src/components/editor/ui/table-handle/index.ts b/preact-full/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/preact-full/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/preact-full/src/components/editor/ui/table-handle/table-handle.tsx b/preact-full/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..6182b185c6 --- /dev/null +++ b/preact-full/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,186 @@ +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/preact' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/preact/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/preact/table-handle' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props) { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + {state.addTableColumnBefore.canExec && ( + + Insert Left + + )} + {state.addTableColumnAfter.canExec && ( + + Insert Right + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableColumn.canExec && ( + + Delete Column + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+ + + + +
+
+ + + {state.addTableRowAbove.canExec && ( + + Insert Above + + )} + {state.addTableRowBelow.canExec && ( + + Insert Below + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableRow.canExec && ( + + Delete Row + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+
+ ) +} diff --git a/preact-full/src/components/editor/ui/tag-menu/index.ts b/preact-full/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..d344b33a70 --- /dev/null +++ b/preact-full/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu' diff --git a/preact-full/src/components/editor/ui/tag-menu/tag-menu.tsx b/preact-full/src/components/editor/ui/tag-menu/tag-menu.tsx new file mode 100644 index 0000000000..00b3e4b085 --- /dev/null +++ b/preact-full/src/components/editor/ui/tag-menu/tag-menu.tsx @@ -0,0 +1,52 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/preact' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/preact/autocomplete' + +const regex = /#[\da-z]*$/i + +export default function TagMenu(props: { + tags: { id: number; label: string }[] +}) { + const editor = useEditor>() + + const handleTagInsert = (id: number, label: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '#' + label, + kind: 'tag', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + + + +
+ + No results + + + {props.tags.map((tag) => ( + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + ))} +
+
+
+
+ ) +} diff --git a/preact-full/src/components/editor/ui/toolbar/index.ts b/preact-full/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-full/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-full/src/components/editor/ui/toolbar/toolbar.tsx b/preact-full/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-full/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-full/src/components/editor/ui/user-menu/index.ts b/preact-full/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/preact-full/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/preact-full/src/components/editor/ui/user-menu/user-menu.tsx b/preact-full/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..39b78adbde --- /dev/null +++ b/preact-full/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,62 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/preact' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/preact/autocomplete' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}) { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + {props.users.map((user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + ))} +
+
+
+
+ ) +} diff --git a/preact-full/src/main.tsx b/preact-full/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-full/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-full/tsconfig.app.json b/preact-full/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-full/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-full/tsconfig.json b/preact-full/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-full/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-full/tsconfig.node.json b/preact-full/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-full/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-full/vite.config.ts b/preact-full/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-full/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-gap-cursor/.gitignore b/preact-gap-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-gap-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-gap-cursor/README.md b/preact-gap-cursor/README.md new file mode 100644 index 0000000000..62c34e646b --- /dev/null +++ b/preact-gap-cursor/README.md @@ -0,0 +1,15 @@ +# preact-gap-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-gap-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-gap-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-gap-cursor preact-gap-cursor +cd preact-gap-cursor +npm install +npm run dev +``` diff --git a/preact-gap-cursor/index.html b/preact-gap-cursor/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-gap-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-gap-cursor/package.json b/preact-gap-cursor/package.json new file mode 100644 index 0000000000..8b316bfbeb --- /dev/null +++ b/preact-gap-cursor/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-gap-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-gap-cursor/src/App.tsx b/preact-gap-cursor/src/App.tsx new file mode 100644 index 0000000000..ed7e74417e --- /dev/null +++ b/preact-gap-cursor/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/gap-cursor' + +export default function App() { + return +} diff --git a/preact-gap-cursor/src/app.css b/preact-gap-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-gap-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx b/preact-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx new file mode 100644 index 0000000000..ddb07f62cb --- /dev/null +++ b/preact-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx @@ -0,0 +1,34 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-gap-cursor' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + return createEditor({ extension: defineExtension(), defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/preact-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts new file mode 100644 index 0000000000..599497170d --- /dev/null +++ b/preact-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts @@ -0,0 +1,19 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineGapCursor(), + defineImage(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/preact-gap-cursor/src/components/editor/examples/gap-cursor/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-gap-cursor/src/components/editor/examples/gap-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/preact-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts new file mode 100644 index 0000000000..e40ee2a83b --- /dev/null +++ b/preact-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts @@ -0,0 +1,28 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + ], +} diff --git a/preact-gap-cursor/src/main.tsx b/preact-gap-cursor/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-gap-cursor/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-gap-cursor/tsconfig.app.json b/preact-gap-cursor/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-gap-cursor/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-gap-cursor/tsconfig.json b/preact-gap-cursor/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-gap-cursor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-gap-cursor/tsconfig.node.json b/preact-gap-cursor/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-gap-cursor/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-gap-cursor/vite.config.ts b/preact-gap-cursor/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-gap-cursor/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-hard-break/.gitignore b/preact-hard-break/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-hard-break/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-hard-break/README.md b/preact-hard-break/README.md new file mode 100644 index 0000000000..d0c6428d7b --- /dev/null +++ b/preact-hard-break/README.md @@ -0,0 +1,15 @@ +# preact-hard-break + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-hard-break) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-hard-break) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-hard-break preact-hard-break +cd preact-hard-break +npm install +npm run dev +``` diff --git a/preact-hard-break/index.html b/preact-hard-break/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-hard-break/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-hard-break/package.json b/preact-hard-break/package.json new file mode 100644 index 0000000000..bf1dc4403d --- /dev/null +++ b/preact-hard-break/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-hard-break", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-hard-break/src/App.tsx b/preact-hard-break/src/App.tsx new file mode 100644 index 0000000000..db3ea90c2a --- /dev/null +++ b/preact-hard-break/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/hard-break' + +export default function App() { + return +} diff --git a/preact-hard-break/src/app.css b/preact-hard-break/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-hard-break/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-hard-break/src/components/editor/examples/hard-break/editor.tsx b/preact-hard-break/src/components/editor/examples/hard-break/editor.tsx new file mode 100644 index 0000000000..7a5fdb265c --- /dev/null +++ b/preact-hard-break/src/components/editor/examples/hard-break/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-hard-break' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-hard-break/src/components/editor/examples/hard-break/extension.ts b/preact-hard-break/src/components/editor/examples/hard-break/extension.ts new file mode 100644 index 0000000000..cad2881056 --- /dev/null +++ b/preact-hard-break/src/components/editor/examples/hard-break/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHardBreak } from 'prosekit/extensions/hard-break' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHardBreak(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-hard-break/src/components/editor/examples/hard-break/index.ts b/preact-hard-break/src/components/editor/examples/hard-break/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-hard-break/src/components/editor/examples/hard-break/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-hard-break/src/components/editor/examples/hard-break/toolbar.tsx b/preact-hard-break/src/components/editor/examples/hard-break/toolbar.tsx new file mode 100644 index 0000000000..c8ee2d5b4f --- /dev/null +++ b/preact-hard-break/src/components/editor/examples/hard-break/toolbar.tsx @@ -0,0 +1,31 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + hardBreak: { + canExec: editor.commands.insertHardBreak.canExec(), + command: () => editor.commands.insertHardBreak(), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/preact-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/preact-hard-break/src/components/editor/sample/sample-doc-hard-break.ts new file mode 100644 index 0000000000..e1c9786b72 --- /dev/null +++ b/preact-hard-break/src/components/editor/sample/sample-doc-hard-break.ts @@ -0,0 +1,68 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: "O'er all the hilltops", + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Is quiet now,', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'In all the treetops', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hearest thou', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hardly a breath;', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'The birds are asleep in the trees:', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Wait, soon like these', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Thou too shalt rest.', + }, + { + type: 'hardBreak', + }, + ], + }, + ], +} diff --git a/preact-hard-break/src/components/editor/ui/button/button.tsx b/preact-hard-break/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-hard-break/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-hard-break/src/components/editor/ui/button/index.ts b/preact-hard-break/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-hard-break/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-hard-break/src/main.tsx b/preact-hard-break/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-hard-break/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-hard-break/tsconfig.app.json b/preact-hard-break/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-hard-break/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-hard-break/tsconfig.json b/preact-hard-break/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-hard-break/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-hard-break/tsconfig.node.json b/preact-hard-break/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-hard-break/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-hard-break/vite.config.ts b/preact-hard-break/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-hard-break/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-heading/.gitignore b/preact-heading/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-heading/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-heading/README.md b/preact-heading/README.md new file mode 100644 index 0000000000..521ea11cee --- /dev/null +++ b/preact-heading/README.md @@ -0,0 +1,15 @@ +# preact-heading + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-heading) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-heading) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-heading preact-heading +cd preact-heading +npm install +npm run dev +``` diff --git a/preact-heading/index.html b/preact-heading/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-heading/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-heading/package.json b/preact-heading/package.json new file mode 100644 index 0000000000..cbeea72dc0 --- /dev/null +++ b/preact-heading/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-heading", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-heading/src/App.tsx b/preact-heading/src/App.tsx new file mode 100644 index 0000000000..c70e72d05f --- /dev/null +++ b/preact-heading/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/heading' + +export default function App() { + return +} diff --git a/preact-heading/src/app.css b/preact-heading/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-heading/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-heading/src/components/editor/examples/heading/editor.tsx b/preact-heading/src/components/editor/examples/heading/editor.tsx new file mode 100644 index 0000000000..dfd25406b3 --- /dev/null +++ b/preact-heading/src/components/editor/examples/heading/editor.tsx @@ -0,0 +1,36 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-heading' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + return createEditor({ extension: defineExtension(), defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-heading/src/components/editor/examples/heading/extension.ts b/preact-heading/src/components/editor/examples/heading/extension.ts new file mode 100644 index 0000000000..e4f8e6ace0 --- /dev/null +++ b/preact-heading/src/components/editor/examples/heading/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHeading(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-heading/src/components/editor/examples/heading/index.ts b/preact-heading/src/components/editor/examples/heading/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-heading/src/components/editor/examples/heading/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-heading/src/components/editor/sample/sample-doc-heading.ts b/preact-heading/src/components/editor/sample/sample-doc-heading.ts new file mode 100644 index 0000000000..210497e633 --- /dev/null +++ b/preact-heading/src/components/editor/sample/sample-doc-heading.ts @@ -0,0 +1,23 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'H1' }], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'H2' }], + }, + { + type: 'heading', + attrs: { level: 3 }, + content: [{ type: 'text', text: 'H3' }], + }, + { type: 'paragraph', content: [] }, + ], +} diff --git a/preact-heading/src/components/editor/ui/button/button.tsx b/preact-heading/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-heading/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-heading/src/components/editor/ui/button/index.ts b/preact-heading/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-heading/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-heading/src/components/editor/ui/image-upload-popover/index.ts b/preact-heading/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-heading/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-heading/src/components/editor/ui/toolbar/index.ts b/preact-heading/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-heading/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-heading/src/components/editor/ui/toolbar/toolbar.tsx b/preact-heading/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-heading/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-heading/src/main.tsx b/preact-heading/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-heading/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-heading/tsconfig.app.json b/preact-heading/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-heading/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-heading/tsconfig.json b/preact-heading/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-heading/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-heading/tsconfig.node.json b/preact-heading/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-heading/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-heading/vite.config.ts b/preact-heading/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-heading/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-highlight/.gitignore b/preact-highlight/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-highlight/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-highlight/README.md b/preact-highlight/README.md new file mode 100644 index 0000000000..72e9564ce9 --- /dev/null +++ b/preact-highlight/README.md @@ -0,0 +1,15 @@ +# preact-highlight + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-highlight) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-highlight) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-highlight preact-highlight +cd preact-highlight +npm install +npm run dev +``` diff --git a/preact-highlight/index.html b/preact-highlight/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-highlight/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-highlight/package.json b/preact-highlight/package.json new file mode 100644 index 0000000000..b977f4c710 --- /dev/null +++ b/preact-highlight/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-highlight", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-highlight/src/App.tsx b/preact-highlight/src/App.tsx new file mode 100644 index 0000000000..2509b001f7 --- /dev/null +++ b/preact-highlight/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/highlight' + +export default function App() { + return +} diff --git a/preact-highlight/src/app.css b/preact-highlight/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-highlight/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-highlight/src/components/editor/examples/highlight/editor.tsx b/preact-highlight/src/components/editor/examples/highlight/editor.tsx new file mode 100644 index 0000000000..fd63d28e8c --- /dev/null +++ b/preact-highlight/src/components/editor/examples/highlight/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-highlight' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-highlight/src/components/editor/examples/highlight/extension.ts b/preact-highlight/src/components/editor/examples/highlight/extension.ts new file mode 100644 index 0000000000..abc131c3be --- /dev/null +++ b/preact-highlight/src/components/editor/examples/highlight/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHighlight } from 'prosekit/extensions/highlight' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHighlight(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-highlight/src/components/editor/examples/highlight/index.ts b/preact-highlight/src/components/editor/examples/highlight/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-highlight/src/components/editor/examples/highlight/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-highlight/src/components/editor/examples/highlight/toolbar.tsx b/preact-highlight/src/components/editor/examples/highlight/toolbar.tsx new file mode 100644 index 0000000000..66b03a127f --- /dev/null +++ b/preact-highlight/src/components/editor/examples/highlight/toolbar.tsx @@ -0,0 +1,32 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + highlight: { + isActive: editor.marks.highlight.isActive(), + canExec: editor.commands.toggleHighlight.canExec(), + command: () => editor.commands.toggleHighlight(), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/preact-highlight/src/components/editor/sample/sample-doc-highlight.ts b/preact-highlight/src/components/editor/sample/sample-doc-highlight.ts new file mode 100644 index 0000000000..0de1a1f7b2 --- /dev/null +++ b/preact-highlight/src/components/editor/sample/sample-doc-highlight.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'highlight', + }, + ], + text: 'This is highlighted text', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/preact-highlight/src/components/editor/ui/button/button.tsx b/preact-highlight/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-highlight/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-highlight/src/components/editor/ui/button/index.ts b/preact-highlight/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-highlight/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-highlight/src/main.tsx b/preact-highlight/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-highlight/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-highlight/tsconfig.app.json b/preact-highlight/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-highlight/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-highlight/tsconfig.json b/preact-highlight/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-highlight/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-highlight/tsconfig.node.json b/preact-highlight/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-highlight/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-highlight/vite.config.ts b/preact-highlight/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-highlight/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-horizontal-rule/.gitignore b/preact-horizontal-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-horizontal-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-horizontal-rule/README.md b/preact-horizontal-rule/README.md new file mode 100644 index 0000000000..007b59f8ee --- /dev/null +++ b/preact-horizontal-rule/README.md @@ -0,0 +1,15 @@ +# preact-horizontal-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-horizontal-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-horizontal-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-horizontal-rule preact-horizontal-rule +cd preact-horizontal-rule +npm install +npm run dev +``` diff --git a/preact-horizontal-rule/index.html b/preact-horizontal-rule/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-horizontal-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-horizontal-rule/package.json b/preact-horizontal-rule/package.json new file mode 100644 index 0000000000..0e04aac6b7 --- /dev/null +++ b/preact-horizontal-rule/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-horizontal-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-horizontal-rule/src/App.tsx b/preact-horizontal-rule/src/App.tsx new file mode 100644 index 0000000000..974e387364 --- /dev/null +++ b/preact-horizontal-rule/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/horizontal-rule' + +export default function App() { + return +} diff --git a/preact-horizontal-rule/src/app.css b/preact-horizontal-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-horizontal-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx new file mode 100644 index 0000000000..47be0af302 --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx @@ -0,0 +1,30 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + return createEditor({ extension: defineExtension() }) + }, []) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts new file mode 100644 index 0000000000..49b6121eeb --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHorizontalRule(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-horizontal-rule/src/components/editor/ui/button/button.tsx b/preact-horizontal-rule/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-horizontal-rule/src/components/editor/ui/button/index.ts b/preact-horizontal-rule/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/preact-horizontal-rule/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx b/preact-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-horizontal-rule/src/main.tsx b/preact-horizontal-rule/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-horizontal-rule/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-horizontal-rule/tsconfig.app.json b/preact-horizontal-rule/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-horizontal-rule/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-horizontal-rule/tsconfig.json b/preact-horizontal-rule/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-horizontal-rule/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-horizontal-rule/tsconfig.node.json b/preact-horizontal-rule/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-horizontal-rule/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-horizontal-rule/vite.config.ts b/preact-horizontal-rule/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-horizontal-rule/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-image-view/.gitignore b/preact-image-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-image-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-image-view/README.md b/preact-image-view/README.md new file mode 100644 index 0000000000..11e4af847a --- /dev/null +++ b/preact-image-view/README.md @@ -0,0 +1,15 @@ +# preact-image-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-image-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-image-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-image-view preact-image-view +cd preact-image-view +npm install +npm run dev +``` diff --git a/preact-image-view/index.html b/preact-image-view/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-image-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-image-view/package.json b/preact-image-view/package.json new file mode 100644 index 0000000000..9fdee631cc --- /dev/null +++ b/preact-image-view/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-image-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-image-view/src/App.tsx b/preact-image-view/src/App.tsx new file mode 100644 index 0000000000..46ede58891 --- /dev/null +++ b/preact-image-view/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/image-view' + +export default function App() { + return +} diff --git a/preact-image-view/src/app.css b/preact-image-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-image-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-image-view/src/components/editor/examples/image-view/editor.tsx b/preact-image-view/src/components/editor/examples/image-view/editor.tsx new file mode 100644 index 0000000000..87f1aefb88 --- /dev/null +++ b/preact-image-view/src/components/editor/examples/image-view/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-image' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-image-view/src/components/editor/examples/image-view/extension.ts b/preact-image-view/src/components/editor/examples/image-view/extension.ts new file mode 100644 index 0000000000..a21febf634 --- /dev/null +++ b/preact-image-view/src/components/editor/examples/image-view/extension.ts @@ -0,0 +1,18 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineImageUploadHandler } from 'prosekit/extensions/image' + +import { sampleUploader } from '../../sample/sample-uploader' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-image-view/src/components/editor/examples/image-view/index.ts b/preact-image-view/src/components/editor/examples/image-view/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-image-view/src/components/editor/examples/image-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-image-view/src/components/editor/sample/sample-doc-image.ts b/preact-image-view/src/components/editor/sample/sample-doc-image.ts new file mode 100644 index 0000000000..c97628339d --- /dev/null +++ b/preact-image-view/src/components/editor/sample/sample-doc-image.ts @@ -0,0 +1,32 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Paste or drop an image to upload it.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/white/200x200/1', + width: 160, + height: 160, + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/640x360/42', + width: 240, + height: 135, + }, + }, + ], +} diff --git a/preact-image-view/src/components/editor/sample/sample-uploader.ts b/preact-image-view/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/preact-image-view/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/preact-image-view/src/components/editor/ui/image-view/image-view.tsx b/preact-image-view/src/components/editor/ui/image-view/image-view.tsx new file mode 100644 index 0000000000..1b83843d1a --- /dev/null +++ b/preact-image-view/src/components/editor/ui/image-view/image-view.tsx @@ -0,0 +1,95 @@ +import type { JSX } from 'preact' +import { useEffect, useState } from 'preact/hooks' +import { UploadTask } from 'prosekit/extensions/file' +import type { ImageAttrs } from 'prosekit/extensions/image' +import type { PreactNodeViewProps } from 'prosekit/preact' +import { ResizableHandle, ResizableRoot } from 'prosekit/preact/resizable' + +export default function ImageView(props: PreactNodeViewProps) { + const attrs = props.node.attrs as ImageAttrs + const url = attrs.src || '' + const uploading = url.startsWith('blob:') + + const [aspectRatio, setAspectRatio] = useState() + const [error, setError] = useState() + const [progress, setProgress] = useState(0) + + useEffect(() => { + if (!uploading) return + + const uploadTask = UploadTask.get(url) + if (!uploadTask) return + + let canceled = false + + uploadTask.finished.catch((error) => { + if (canceled) return + setError(String(error)) + }) + const unsubscribeProgress = uploadTask.subscribeProgress( + ({ loaded, total }) => { + if (canceled) return + setProgress(total ? loaded / total : 0) + }, + ) + + return () => { + canceled = true + unsubscribeProgress() + } + }, [url, uploading]) + + const handleImageLoad = ( + event: JSX.TargetedEvent, + ) => { + const img = event.currentTarget + const { naturalWidth, naturalHeight } = img + const ratio = naturalWidth / naturalHeight + if (ratio && Number.isFinite(ratio)) { + setAspectRatio(ratio) + } + if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) { + props.setAttrs({ width: naturalWidth, height: naturalHeight }) + } + } + + return ( + props.setAttrs(event.detail)} + data-selected={props.selected ? '' : undefined} + className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid" + > + {url && !error && ( + upload preview + )} + {uploading && !error && ( +
+
+
{Math.round(progress * 100)}%
+
+ )} + {error && ( +
+
+
+ Failed to upload image +
+
+ )} + +
+
+
+ ) +} diff --git a/preact-image-view/src/components/editor/ui/image-view/index.ts b/preact-image-view/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..2b8200267d --- /dev/null +++ b/preact-image-view/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + definePreactNodeView, + type PreactNodeViewComponent, +} from 'prosekit/preact' + +import ImageView from './image-view' + +export function defineImageView(): Extension { + return definePreactNodeView({ + name: 'image', + component: ImageView satisfies PreactNodeViewComponent, + }) +} diff --git a/preact-image-view/src/main.tsx b/preact-image-view/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-image-view/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-image-view/tsconfig.app.json b/preact-image-view/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-image-view/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-image-view/tsconfig.json b/preact-image-view/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-image-view/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-image-view/tsconfig.node.json b/preact-image-view/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-image-view/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-image-view/vite.config.ts b/preact-image-view/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-image-view/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-inline-menu/.gitignore b/preact-inline-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-inline-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-inline-menu/README.md b/preact-inline-menu/README.md new file mode 100644 index 0000000000..68bb759fbe --- /dev/null +++ b/preact-inline-menu/README.md @@ -0,0 +1,15 @@ +# preact-inline-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-inline-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-inline-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-inline-menu preact-inline-menu +cd preact-inline-menu +npm install +npm run dev +``` diff --git a/preact-inline-menu/index.html b/preact-inline-menu/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-inline-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-inline-menu/package.json b/preact-inline-menu/package.json new file mode 100644 index 0000000000..03c65e03cf --- /dev/null +++ b/preact-inline-menu/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-inline-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-inline-menu/src/App.tsx b/preact-inline-menu/src/App.tsx new file mode 100644 index 0000000000..660285db3c --- /dev/null +++ b/preact-inline-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/inline-menu' + +export default function App() { + return +} diff --git a/preact-inline-menu/src/app.css b/preact-inline-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-inline-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-inline-menu/src/components/editor/examples/inline-menu/editor.tsx b/preact-inline-menu/src/components/editor/examples/inline-menu/editor.tsx new file mode 100644 index 0000000000..47a9f7334d --- /dev/null +++ b/preact-inline-menu/src/components/editor/examples/inline-menu/editor.tsx @@ -0,0 +1,36 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-inline-menu' +import { InlineMenu } from '../../ui/inline-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + return createEditor({ extension: defineExtension(), defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/preact-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/preact-inline-menu/src/components/editor/examples/inline-menu/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/preact-inline-menu/src/components/editor/examples/inline-menu/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/preact-inline-menu/src/components/editor/examples/inline-menu/index.ts b/preact-inline-menu/src/components/editor/examples/inline-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-inline-menu/src/components/editor/examples/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/preact-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts new file mode 100644 index 0000000000..62a5984cb0 --- /dev/null +++ b/preact-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts @@ -0,0 +1,33 @@ +import type { NodeJSON } from 'prosekit/core' + +const loremText = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'Try to select some text', + }, + ], + }, + ...Array.from({ length: 10 }, () => ({ + type: 'paragraph' as const, + content: [ + { + type: 'text' as const, + text: loremText, + }, + ], + })), + ], +} diff --git a/preact-inline-menu/src/components/editor/ui/button/button.tsx b/preact-inline-menu/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-inline-menu/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-inline-menu/src/components/editor/ui/button/index.ts b/preact-inline-menu/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-inline-menu/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-inline-menu/src/components/editor/ui/inline-menu/index.ts b/preact-inline-menu/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/preact-inline-menu/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/preact-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..a014b74f57 --- /dev/null +++ b/preact-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +import type { JSX } from 'preact' +import { useState } from 'preact/hooks' +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/preact' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/preact/inline-popover' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + const handleSubmit = ( + event: JSX.TargetedEvent, + ) => { + event.preventDefault() + const href = event.currentTarget.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
+ +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/preact-inline-menu/src/main.tsx b/preact-inline-menu/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-inline-menu/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-inline-menu/tsconfig.app.json b/preact-inline-menu/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-inline-menu/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-inline-menu/tsconfig.json b/preact-inline-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-inline-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-inline-menu/tsconfig.node.json b/preact-inline-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-inline-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-inline-menu/vite.config.ts b/preact-inline-menu/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-inline-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-italic/.gitignore b/preact-italic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-italic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-italic/README.md b/preact-italic/README.md new file mode 100644 index 0000000000..bf98e2b49a --- /dev/null +++ b/preact-italic/README.md @@ -0,0 +1,15 @@ +# preact-italic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-italic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-italic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-italic preact-italic +cd preact-italic +npm install +npm run dev +``` diff --git a/preact-italic/index.html b/preact-italic/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-italic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-italic/package.json b/preact-italic/package.json new file mode 100644 index 0000000000..0d4afa3739 --- /dev/null +++ b/preact-italic/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-italic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-italic/src/App.tsx b/preact-italic/src/App.tsx new file mode 100644 index 0000000000..7ce968b449 --- /dev/null +++ b/preact-italic/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/italic' + +export default function App() { + return +} diff --git a/preact-italic/src/app.css b/preact-italic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-italic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-italic/src/components/editor/examples/italic/editor.tsx b/preact-italic/src/components/editor/examples/italic/editor.tsx new file mode 100644 index 0000000000..519ef5ddec --- /dev/null +++ b/preact-italic/src/components/editor/examples/italic/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-italic' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-italic/src/components/editor/examples/italic/extension.ts b/preact-italic/src/components/editor/examples/italic/extension.ts new file mode 100644 index 0000000000..a456b06aad --- /dev/null +++ b/preact-italic/src/components/editor/examples/italic/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineItalic(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-italic/src/components/editor/examples/italic/index.ts b/preact-italic/src/components/editor/examples/italic/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-italic/src/components/editor/examples/italic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-italic/src/components/editor/sample/sample-doc-italic.ts b/preact-italic/src/components/editor/sample/sample-doc-italic.ts new file mode 100644 index 0000000000..fb99415b2c --- /dev/null +++ b/preact-italic/src/components/editor/sample/sample-doc-italic.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/preact-italic/src/components/editor/ui/button/button.tsx b/preact-italic/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-italic/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-italic/src/components/editor/ui/button/index.ts b/preact-italic/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-italic/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-italic/src/components/editor/ui/image-upload-popover/index.ts b/preact-italic/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-italic/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-italic/src/components/editor/ui/toolbar/index.ts b/preact-italic/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-italic/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-italic/src/components/editor/ui/toolbar/toolbar.tsx b/preact-italic/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-italic/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-italic/src/main.tsx b/preact-italic/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-italic/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-italic/tsconfig.app.json b/preact-italic/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-italic/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-italic/tsconfig.json b/preact-italic/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-italic/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-italic/tsconfig.node.json b/preact-italic/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-italic/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-italic/vite.config.ts b/preact-italic/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-italic/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-katex/.gitignore b/preact-katex/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-katex/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-katex/README.md b/preact-katex/README.md new file mode 100644 index 0000000000..ec9783e8d1 --- /dev/null +++ b/preact-katex/README.md @@ -0,0 +1,15 @@ +# preact-katex + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-katex) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-katex) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-katex preact-katex +cd preact-katex +npm install +npm run dev +``` diff --git a/preact-katex/index.html b/preact-katex/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-katex/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-katex/package.json b/preact-katex/package.json new file mode 100644 index 0000000000..226b66e563 --- /dev/null +++ b/preact-katex/package.json @@ -0,0 +1,26 @@ +{ + "name": "example-preact-katex", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-katex/src/App.tsx b/preact-katex/src/App.tsx new file mode 100644 index 0000000000..2a28c7c7d7 --- /dev/null +++ b/preact-katex/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/katex' + +export default function App() { + return +} diff --git a/preact-katex/src/app.css b/preact-katex/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-katex/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-katex/src/components/editor/examples/katex/editor.tsx b/preact-katex/src/components/editor/examples/katex/editor.tsx new file mode 100644 index 0000000000..89009d34a9 --- /dev/null +++ b/preact-katex/src/components/editor/examples/katex/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-tex' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-katex/src/components/editor/examples/katex/extension.ts b/preact-katex/src/components/editor/examples/katex/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/preact-katex/src/components/editor/examples/katex/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-katex/src/components/editor/examples/katex/index.ts b/preact-katex/src/components/editor/examples/katex/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-katex/src/components/editor/examples/katex/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-katex/src/components/editor/sample/katex.ts b/preact-katex/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/preact-katex/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/preact-katex/src/components/editor/sample/sample-doc-tex.ts b/preact-katex/src/components/editor/sample/sample-doc-tex.ts new file mode 100644 index 0000000000..21ccf3e94e --- /dev/null +++ b/preact-katex/src/components/editor/sample/sample-doc-tex.ts @@ -0,0 +1,60 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Inline equations' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Block equations' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: 'The Gaussian integral:' }], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + ], +} diff --git a/preact-katex/src/main.tsx b/preact-katex/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-katex/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-katex/tsconfig.app.json b/preact-katex/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-katex/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-katex/tsconfig.json b/preact-katex/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-katex/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-katex/tsconfig.node.json b/preact-katex/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-katex/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-katex/vite.config.ts b/preact-katex/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-katex/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-keymap/.gitignore b/preact-keymap/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-keymap/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-keymap/README.md b/preact-keymap/README.md new file mode 100644 index 0000000000..a5ef706978 --- /dev/null +++ b/preact-keymap/README.md @@ -0,0 +1,15 @@ +# preact-keymap + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-keymap) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-keymap) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-keymap preact-keymap +cd preact-keymap +npm install +npm run dev +``` diff --git a/preact-keymap/index.html b/preact-keymap/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-keymap/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-keymap/package.json b/preact-keymap/package.json new file mode 100644 index 0000000000..f0b705a45a --- /dev/null +++ b/preact-keymap/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-keymap", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-keymap/src/App.tsx b/preact-keymap/src/App.tsx new file mode 100644 index 0000000000..da3b6ebb09 --- /dev/null +++ b/preact-keymap/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/keymap' + +export default function App() { + return +} diff --git a/preact-keymap/src/app.css b/preact-keymap/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-keymap/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-keymap/src/components/editor/examples/keymap/editor.tsx b/preact-keymap/src/components/editor/examples/keymap/editor.tsx new file mode 100644 index 0000000000..18982a10fe --- /dev/null +++ b/preact-keymap/src/components/editor/examples/keymap/editor.tsx @@ -0,0 +1,52 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useCallback, useMemo, useState } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + const [submissions, setSubmissions] = useState([]) + + const pushSubmission = useCallback( + (hotkey: string) => { + const docString = JSON.stringify(editor.getDocJSON()) + const submission = `${new Date().toISOString()}\t${hotkey}\n${docString}` + setSubmissions((prev) => [...prev, submission]) + }, + [editor], + ) + + return ( + +
+ +
+
+
+
+
+ Submit Records +
    + {submissions.map((submission, index) => ( +
  1. +
    {submission}
    +
  2. + ))} +
+ {submissions.length === 0 &&
No submissions yet
} +
+
+ ) +} diff --git a/preact-keymap/src/components/editor/examples/keymap/extension.ts b/preact-keymap/src/components/editor/examples/keymap/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/preact-keymap/src/components/editor/examples/keymap/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/preact-keymap/src/components/editor/examples/keymap/index.ts b/preact-keymap/src/components/editor/examples/keymap/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-keymap/src/components/editor/examples/keymap/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-keymap/src/components/editor/examples/keymap/toolbar.tsx b/preact-keymap/src/components/editor/examples/keymap/toolbar.tsx new file mode 100644 index 0000000000..59664071d7 --- /dev/null +++ b/preact-keymap/src/components/editor/examples/keymap/toolbar.tsx @@ -0,0 +1,27 @@ +import { useState } from 'preact/hooks' + +import { Button } from '../../ui/button' + +import { useSubmitKeymap } from './use-submit-keymap' + +export default function Toolbar(props: { onSubmit: (hotkey: string) => void }) { + const [hotkey, setHotkey] = useState<'Shift-Enter' | 'Enter'>('Shift-Enter') + useSubmitKeymap(hotkey, props.onSubmit) + + return ( +
+ + + +
+ ) +} diff --git a/preact-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts b/preact-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts new file mode 100644 index 0000000000..4f10405e56 --- /dev/null +++ b/preact-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts @@ -0,0 +1,19 @@ +import { useMemo } from 'preact/hooks' +import type { Keymap } from 'prosekit/core' +import { useKeymap } from 'prosekit/preact' + +export function useSubmitKeymap( + hotkey: 'Shift-Enter' | 'Enter', + onSubmit: (hotkey: string) => void, +) { + const keymap: Keymap = useMemo(() => { + return { + [hotkey]: () => { + onSubmit(hotkey) + return true + }, + } + }, [hotkey, onSubmit]) + + useKeymap(keymap) +} diff --git a/preact-keymap/src/components/editor/ui/button/button.tsx b/preact-keymap/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-keymap/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-keymap/src/components/editor/ui/button/index.ts b/preact-keymap/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-keymap/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-keymap/src/main.tsx b/preact-keymap/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-keymap/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-keymap/tsconfig.app.json b/preact-keymap/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-keymap/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-keymap/tsconfig.json b/preact-keymap/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-keymap/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-keymap/tsconfig.node.json b/preact-keymap/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-keymap/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-keymap/vite.config.ts b/preact-keymap/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-keymap/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-link-mark-view/.gitignore b/preact-link-mark-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-link-mark-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-link-mark-view/README.md b/preact-link-mark-view/README.md new file mode 100644 index 0000000000..34a7cee8f0 --- /dev/null +++ b/preact-link-mark-view/README.md @@ -0,0 +1,15 @@ +# preact-link-mark-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-link-mark-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-link-mark-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-link-mark-view preact-link-mark-view +cd preact-link-mark-view +npm install +npm run dev +``` diff --git a/preact-link-mark-view/index.html b/preact-link-mark-view/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-link-mark-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-link-mark-view/package.json b/preact-link-mark-view/package.json new file mode 100644 index 0000000000..e5bc864d38 --- /dev/null +++ b/preact-link-mark-view/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-link-mark-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-link-mark-view/src/App.tsx b/preact-link-mark-view/src/App.tsx new file mode 100644 index 0000000000..8a8685678d --- /dev/null +++ b/preact-link-mark-view/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/link-mark-view' + +export default function App() { + return +} diff --git a/preact-link-mark-view/src/app.css b/preact-link-mark-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-link-mark-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx b/preact-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx new file mode 100644 index 0000000000..0d1fb8a3e7 --- /dev/null +++ b/preact-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-link-mark-view' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/preact-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts new file mode 100644 index 0000000000..c9c2d7f7c1 --- /dev/null +++ b/preact-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePreactMarkView } from 'prosekit/preact' + +import LinkView from './link-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePreactMarkView({ + name: 'link', + component: LinkView, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/preact-link-mark-view/src/components/editor/examples/link-mark-view/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-link-mark-view/src/components/editor/examples/link-mark-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx b/preact-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx new file mode 100644 index 0000000000..14de85477b --- /dev/null +++ b/preact-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx @@ -0,0 +1,45 @@ +import { useEffect, useState } from 'preact/hooks' +import type { PreactMarkViewProps } from 'prosekit/preact' + +const colors = [ + '#f06292', + '#ba68c8', + '#9575cd', + '#7986cb', + '#64b5f6', + '#4fc3f7', + '#4dd0e1', + '#4db6ac', + '#81c784', + '#aed581', + '#ffb74d', + '#ffa726', + '#ff8a65', + '#d4e157', + '#ffd54f', + '#ffecb3', +] as const + +function pickRandomColor() { + return colors[Math.floor(Math.random() * colors.length)] +} + +export default function Link(props: PreactMarkViewProps) { + const [color, setColor] = useState(colors[0]) + const href = props.mark.attrs.href as string + + useEffect(() => { + const interval = setInterval(() => { + setColor(pickRandomColor()) + }, 1000) + return () => clearInterval(interval) + }, []) + + return ( + + ) +} diff --git a/preact-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/preact-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts new file mode 100644 index 0000000000..57abd09dd6 --- /dev/null +++ b/preact-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is a link that changes color every second: ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/preact-link-mark-view/src/main.tsx b/preact-link-mark-view/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-link-mark-view/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-link-mark-view/tsconfig.app.json b/preact-link-mark-view/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-link-mark-view/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-link-mark-view/tsconfig.json b/preact-link-mark-view/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-link-mark-view/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-link-mark-view/tsconfig.node.json b/preact-link-mark-view/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-link-mark-view/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-link-mark-view/vite.config.ts b/preact-link-mark-view/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-link-mark-view/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-link/.gitignore b/preact-link/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-link/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-link/README.md b/preact-link/README.md new file mode 100644 index 0000000000..50d7abd9b4 --- /dev/null +++ b/preact-link/README.md @@ -0,0 +1,15 @@ +# preact-link + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-link) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-link) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-link preact-link +cd preact-link +npm install +npm run dev +``` diff --git a/preact-link/index.html b/preact-link/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-link/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-link/package.json b/preact-link/package.json new file mode 100644 index 0000000000..4689422411 --- /dev/null +++ b/preact-link/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-link", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-link/src/App.tsx b/preact-link/src/App.tsx new file mode 100644 index 0000000000..1cf0f24636 --- /dev/null +++ b/preact-link/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/link' + +export default function App() { + return +} diff --git a/preact-link/src/app.css b/preact-link/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-link/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-link/src/components/editor/examples/link/editor.tsx b/preact-link/src/components/editor/examples/link/editor.tsx new file mode 100644 index 0000000000..d8c42d14ee --- /dev/null +++ b/preact-link/src/components/editor/examples/link/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-link' +import { InlineMenu } from '../../ui/inline-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/preact-link/src/components/editor/examples/link/extension.ts b/preact-link/src/components/editor/examples/link/extension.ts new file mode 100644 index 0000000000..bf499147da --- /dev/null +++ b/preact-link/src/components/editor/examples/link/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLink } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-link/src/components/editor/examples/link/index.ts b/preact-link/src/components/editor/examples/link/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-link/src/components/editor/examples/link/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-link/src/components/editor/sample/sample-doc-link.ts b/preact-link/src/components/editor/sample/sample-doc-link.ts new file mode 100644 index 0000000000..726cf334fd --- /dev/null +++ b/preact-link/src/components/editor/sample/sample-doc-link.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is an ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/preact-link/src/components/editor/ui/button/button.tsx b/preact-link/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-link/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-link/src/components/editor/ui/button/index.ts b/preact-link/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-link/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-link/src/components/editor/ui/inline-menu/index.ts b/preact-link/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/preact-link/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/preact-link/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-link/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..a014b74f57 --- /dev/null +++ b/preact-link/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +import type { JSX } from 'preact' +import { useState } from 'preact/hooks' +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/preact' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/preact/inline-popover' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + const handleSubmit = ( + event: JSX.TargetedEvent, + ) => { + event.preventDefault() + const href = event.currentTarget.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
+ +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/preact-link/src/main.tsx b/preact-link/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-link/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-link/tsconfig.app.json b/preact-link/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-link/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-link/tsconfig.json b/preact-link/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-link/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-link/tsconfig.node.json b/preact-link/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-link/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-link/vite.config.ts b/preact-link/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-link/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-list-custom-checkbox/.gitignore b/preact-list-custom-checkbox/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-list-custom-checkbox/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-list-custom-checkbox/README.md b/preact-list-custom-checkbox/README.md new file mode 100644 index 0000000000..bf2504dd3a --- /dev/null +++ b/preact-list-custom-checkbox/README.md @@ -0,0 +1,15 @@ +# preact-list-custom-checkbox + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-list-custom-checkbox) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-list-custom-checkbox) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-list-custom-checkbox preact-list-custom-checkbox +cd preact-list-custom-checkbox +npm install +npm run dev +``` diff --git a/preact-list-custom-checkbox/index.html b/preact-list-custom-checkbox/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-list-custom-checkbox/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-list-custom-checkbox/package.json b/preact-list-custom-checkbox/package.json new file mode 100644 index 0000000000..2020a7c4e6 --- /dev/null +++ b/preact-list-custom-checkbox/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-list-custom-checkbox", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-list-custom-checkbox/src/App.tsx b/preact-list-custom-checkbox/src/App.tsx new file mode 100644 index 0000000000..96b82e9a84 --- /dev/null +++ b/preact-list-custom-checkbox/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/list-custom-checkbox' + +export default function App() { + return +} diff --git a/preact-list-custom-checkbox/src/app.css b/preact-list-custom-checkbox/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-list-custom-checkbox/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css new file mode 100644 index 0000000000..ec631b72ad --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css @@ -0,0 +1,75 @@ +div[data-custom-list-css-enabled] + .ProseMirror + .prosemirror-flat-list[data-list-kind='task'] { + & > .list-marker label { + box-sizing: border-box; + display: flex; + position: relative; + left: calc(var(--spacing) * -0.5); + align-items: center; + cursor: pointer; + transition: transform 0.15s ease-in-out; + + &:hover { + transform: scale(1.1); + } + + &::after { + position: absolute; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + content: ''; + color: var(--color-white); + opacity: 0; + } + + /* https://api.iconify.design/lucide.css?icons=check */ + &::after { + display: inline-block; + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); + } + + & input { + box-sizing: border-box; + appearance: none; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + margin: 0; + border-width: 1px; + border-style: solid; + border-radius: var(--radius-md); + border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); + box-shadow: var(--shadow-sm); + cursor: pointer; + transition: all 0.15s ease-in-out; + + &:hover { + box-shadow: var(--shadow-md); + } + + &:checked { + border-color: var(--color-red-500); + background-color: var(--color-red-500); + } + } + } + + &[data-list-checked] > .list-marker label { + &::after { + opacity: 1; + } + } + + &[data-list-checked] { + color: var(--color-gray-400); + text-decoration: line-through; + text-decoration-color: var(--color-gray-400); + } +} diff --git a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx new file mode 100644 index 0000000000..e335ddb880 --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx @@ -0,0 +1,44 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import './custom-list.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-list-custom-checkbox' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ + extension, + defaultContent, + }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/preact-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts new file mode 100644 index 0000000000..972611aed1 --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts @@ -0,0 +1,38 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', + }, + { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, + { type: 'text', text: ' for the styles.' }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Completed Task' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Incomplete Task' }], + }, + ], + }, + ], +} diff --git a/preact-list-custom-checkbox/src/components/editor/ui/button/button.tsx b/preact-list-custom-checkbox/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-list-custom-checkbox/src/components/editor/ui/button/index.ts b/preact-list-custom-checkbox/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/preact-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx b/preact-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-list-custom-checkbox/src/main.tsx b/preact-list-custom-checkbox/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-list-custom-checkbox/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-list-custom-checkbox/tsconfig.app.json b/preact-list-custom-checkbox/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-list-custom-checkbox/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-list-custom-checkbox/tsconfig.json b/preact-list-custom-checkbox/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-list-custom-checkbox/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-list-custom-checkbox/tsconfig.node.json b/preact-list-custom-checkbox/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-list-custom-checkbox/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-list-custom-checkbox/vite.config.ts b/preact-list-custom-checkbox/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-list-custom-checkbox/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-list/.gitignore b/preact-list/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-list/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-list/README.md b/preact-list/README.md new file mode 100644 index 0000000000..0817d662fe --- /dev/null +++ b/preact-list/README.md @@ -0,0 +1,15 @@ +# preact-list + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-list) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-list) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-list preact-list +cd preact-list +npm install +npm run dev +``` diff --git a/preact-list/index.html b/preact-list/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-list/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-list/package.json b/preact-list/package.json new file mode 100644 index 0000000000..4395490a90 --- /dev/null +++ b/preact-list/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-list", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-list/src/App.tsx b/preact-list/src/App.tsx new file mode 100644 index 0000000000..73f050ef0c --- /dev/null +++ b/preact-list/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/list' + +export default function App() { + return +} diff --git a/preact-list/src/app.css b/preact-list/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-list/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-list/src/components/editor/examples/list/editor.tsx b/preact-list/src/components/editor/examples/list/editor.tsx new file mode 100644 index 0000000000..f2c6b62a0b --- /dev/null +++ b/preact-list/src/components/editor/examples/list/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-list' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-list/src/components/editor/examples/list/extension.ts b/preact-list/src/components/editor/examples/list/extension.ts new file mode 100644 index 0000000000..f66bae6ff7 --- /dev/null +++ b/preact-list/src/components/editor/examples/list/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineList } from 'prosekit/extensions/list' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineList(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-list/src/components/editor/examples/list/index.ts b/preact-list/src/components/editor/examples/list/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-list/src/components/editor/examples/list/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-list/src/components/editor/sample/sample-doc-list.ts b/preact-list/src/components/editor/sample/sample-doc-list.ts new file mode 100644 index 0000000000..091bc37185 --- /dev/null +++ b/preact-list/src/components/editor/sample/sample-doc-list.ts @@ -0,0 +1,47 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Ordered List' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'toggle', collapsed: true }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, + { + type: 'list', + attrs: { + kind: 'bullet', + }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, + ], + }, + ], + }, + ], +} diff --git a/preact-list/src/components/editor/ui/button/button.tsx b/preact-list/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-list/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-list/src/components/editor/ui/button/index.ts b/preact-list/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-list/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-list/src/components/editor/ui/image-upload-popover/index.ts b/preact-list/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-list/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-list/src/components/editor/ui/toolbar/index.ts b/preact-list/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-list/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-list/src/components/editor/ui/toolbar/toolbar.tsx b/preact-list/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-list/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-list/src/main.tsx b/preact-list/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-list/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-list/tsconfig.app.json b/preact-list/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-list/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-list/tsconfig.json b/preact-list/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-list/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-list/tsconfig.node.json b/preact-list/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-list/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-list/vite.config.ts b/preact-list/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-list/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-loro/.gitignore b/preact-loro/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-loro/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-loro/README.md b/preact-loro/README.md new file mode 100644 index 0000000000..f6e9353595 --- /dev/null +++ b/preact-loro/README.md @@ -0,0 +1,15 @@ +# preact-loro + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-loro) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-loro) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-loro preact-loro +cd preact-loro +npm install +npm run dev +``` diff --git a/preact-loro/index.html b/preact-loro/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-loro/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-loro/package.json b/preact-loro/package.json new file mode 100644 index 0000000000..b472ff7d75 --- /dev/null +++ b/preact-loro/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-preact-loro", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "loro-crdt": "^1.12.1", + "loro-prosemirror": "^0.4.3", + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-wasm": "^3.6.0" + } +} diff --git a/preact-loro/src/App.tsx b/preact-loro/src/App.tsx new file mode 100644 index 0000000000..71d2a6b080 --- /dev/null +++ b/preact-loro/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/loro' + +export default function App() { + return +} diff --git a/preact-loro/src/app.css b/preact-loro/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-loro/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-loro/src/components/editor/examples/loro/editor-component.tsx b/preact-loro/src/components/editor/examples/loro/editor-component.tsx new file mode 100644 index 0000000000..6a46fc6c63 --- /dev/null +++ b/preact-loro/src/components/editor/examples/loro/editor-component.tsx @@ -0,0 +1,36 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/loro/style.css' + +import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function EditorComponent(props: { + loro: LoroDocType + awareness: CursorAwareness +}) { + const editor = useMemo(() => { + const extension = defineExtension(props.loro, props.awareness) + return createEditor({ extension }) + }, [props.loro, props.awareness]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-loro/src/components/editor/examples/loro/editor.tsx b/preact-loro/src/components/editor/examples/loro/editor.tsx new file mode 100644 index 0000000000..909b879634 --- /dev/null +++ b/preact-loro/src/components/editor/examples/loro/editor.tsx @@ -0,0 +1,63 @@ +import { LoroDoc, type AwarenessListener } from 'loro-crdt' +import { CursorAwareness, type LoroDocType } from 'loro-prosemirror' +import { useEffect, useState } from 'preact/hooks' + +import EditorComponent from './editor-component' + +export default function Page() { + const { loroA, awarenessA, loroB, awarenessB } = useLoroDocs() + + return ( +
+ + +
+ ) +} + +function useLoroDocs() { + const [loroState] = useState(() => { + const loroA: LoroDocType = new LoroDoc() + const loroB: LoroDocType = new LoroDoc() + + const idA = loroA.peerIdStr + const idB = loroB.peerIdStr + + const awarenessA = new CursorAwareness(idA) + const awarenessB = new CursorAwareness(idB) + + return { loroA, loroB, idA, idB, awarenessA, awarenessB } + }) + + useEffect(() => { + const { loroA, loroB, idA, idB, awarenessA, awarenessB } = loroState + loroA.import(loroB.export({ mode: 'update' })) + loroB.import(loroA.export({ mode: 'update' })) + const unsubscribeA = loroA.subscribeLocalUpdates((updates) => { + loroB.import(updates) + }) + const unsubscribeB = loroB.subscribeLocalUpdates((updates) => { + loroA.import(updates) + }) + const awarenessAListener: AwarenessListener = (_, origin) => { + if (origin === 'local') { + awarenessB.apply(awarenessA.encode([idA])) + } + } + const awarenessBListener: AwarenessListener = (_, origin) => { + if (origin === 'local') { + awarenessA.apply(awarenessB.encode([idB])) + } + } + awarenessA.addListener(awarenessAListener) + awarenessB.addListener(awarenessBListener) + return () => { + awarenessA.removeListener(awarenessAListener) + awarenessB.removeListener(awarenessBListener) + unsubscribeA() + unsubscribeB() + } + }, [loroState]) + + return loroState +} diff --git a/preact-loro/src/components/editor/examples/loro/extension.ts b/preact-loro/src/components/editor/examples/loro/extension.ts new file mode 100644 index 0000000000..5a85c5e168 --- /dev/null +++ b/preact-loro/src/components/editor/examples/loro/extension.ts @@ -0,0 +1,47 @@ +import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineLoro } from 'prosekit/extensions/loro' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { + return union([ + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineLoro({ doc, awareness }), + ]) +} + +export type EditorExtension = ReturnType diff --git a/preact-loro/src/components/editor/examples/loro/index.ts b/preact-loro/src/components/editor/examples/loro/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-loro/src/components/editor/examples/loro/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-loro/src/components/editor/ui/button/button.tsx b/preact-loro/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-loro/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-loro/src/components/editor/ui/button/index.ts b/preact-loro/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-loro/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-loro/src/components/editor/ui/image-upload-popover/index.ts b/preact-loro/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-loro/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-loro/src/components/editor/ui/toolbar/index.ts b/preact-loro/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-loro/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-loro/src/components/editor/ui/toolbar/toolbar.tsx b/preact-loro/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-loro/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-loro/src/main.tsx b/preact-loro/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-loro/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-loro/tsconfig.app.json b/preact-loro/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-loro/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-loro/tsconfig.json b/preact-loro/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-loro/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-loro/tsconfig.node.json b/preact-loro/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-loro/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-loro/vite.config.ts b/preact-loro/vite.config.ts new file mode 100644 index 0000000000..f0eb068ec3 --- /dev/null +++ b/preact-loro/vite.config.ts @@ -0,0 +1,9 @@ +import wasm from 'vite-plugin-wasm' +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [wasm(), preact(), tailwindcss()], +}) diff --git a/preact-mark-rule/.gitignore b/preact-mark-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-mark-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-mark-rule/README.md b/preact-mark-rule/README.md new file mode 100644 index 0000000000..57ef73b293 --- /dev/null +++ b/preact-mark-rule/README.md @@ -0,0 +1,15 @@ +# preact-mark-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-mark-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-mark-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-mark-rule preact-mark-rule +cd preact-mark-rule +npm install +npm run dev +``` diff --git a/preact-mark-rule/index.html b/preact-mark-rule/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-mark-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-mark-rule/package.json b/preact-mark-rule/package.json new file mode 100644 index 0000000000..303b34f6da --- /dev/null +++ b/preact-mark-rule/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-mark-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-mark-rule/src/App.tsx b/preact-mark-rule/src/App.tsx new file mode 100644 index 0000000000..4e93a4bf60 --- /dev/null +++ b/preact-mark-rule/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/mark-rule' + +export default function App() { + return +} diff --git a/preact-mark-rule/src/app.css b/preact-mark-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-mark-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-mark-rule/src/components/editor/examples/mark-rule/editor.tsx b/preact-mark-rule/src/components/editor/examples/mark-rule/editor.tsx new file mode 100644 index 0000000000..3b01b9885a --- /dev/null +++ b/preact-mark-rule/src/components/editor/examples/mark-rule/editor.tsx @@ -0,0 +1,28 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/preact-mark-rule/src/components/editor/examples/mark-rule/extension.ts new file mode 100644 index 0000000000..4a1de40783 --- /dev/null +++ b/preact-mark-rule/src/components/editor/examples/mark-rule/extension.ts @@ -0,0 +1,32 @@ +import { + defineBaseCommands, + defineBaseKeymap, + defineHistory, + union, +} from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { definePlaceholder } from 'prosekit/extensions/placeholder' +import { defineText } from 'prosekit/extensions/text' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +import { defineIssueLink } from './issue-link' + +export function defineExtension() { + return union( + defineDoc(), + defineText(), + defineParagraph(), + defineHistory(), + defineBaseKeymap(), + defineBaseCommands(), + defineVirtualSelection(), + defineLinkSpec(), + defineLinkMarkRule(), + definePlaceholder({ placeholder: 'Try typing #123' }), + defineIssueLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-mark-rule/src/components/editor/examples/mark-rule/index.ts b/preact-mark-rule/src/components/editor/examples/mark-rule/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-mark-rule/src/components/editor/examples/mark-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/preact-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts new file mode 100644 index 0000000000..3840b5e53d --- /dev/null +++ b/preact-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts @@ -0,0 +1,32 @@ +import { defineMarkSpec, union } from 'prosekit/core' +import { defineMarkRule } from 'prosekit/extensions/mark-rule' + +export function defineIssueLink() { + return union( + defineMarkSpec({ + name: 'issueLink', + inclusive: false, + attrs: { + issueNumber: {}, + }, + toDOM(node) { + const issueNumber = node.attrs.issueNumber as number + return [ + 'a', + { + href: `https://example.com/issues/${issueNumber}`, + title: `Issue #${issueNumber}`, + }, + 0, + ] + }, + }), + defineMarkRule({ + regex: /#(\d+)/g, + type: 'issueLink', + attrs: (match) => { + return { issueNumber: Number.parseInt(match[1] || '0') } + }, + }), + ) +} diff --git a/preact-mark-rule/src/main.tsx b/preact-mark-rule/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-mark-rule/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-mark-rule/tsconfig.app.json b/preact-mark-rule/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-mark-rule/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-mark-rule/tsconfig.json b/preact-mark-rule/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-mark-rule/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-mark-rule/tsconfig.node.json b/preact-mark-rule/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-mark-rule/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-mark-rule/vite.config.ts b/preact-mark-rule/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-mark-rule/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-minimal/.gitignore b/preact-minimal/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-minimal/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-minimal/README.md b/preact-minimal/README.md new file mode 100644 index 0000000000..b3c9f5ee76 --- /dev/null +++ b/preact-minimal/README.md @@ -0,0 +1,15 @@ +# preact-minimal + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-minimal) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-minimal) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-minimal preact-minimal +cd preact-minimal +npm install +npm run dev +``` diff --git a/preact-minimal/index.html b/preact-minimal/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-minimal/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-minimal/package.json b/preact-minimal/package.json new file mode 100644 index 0000000000..9824d8929e --- /dev/null +++ b/preact-minimal/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-minimal/src/App.tsx b/preact-minimal/src/App.tsx new file mode 100644 index 0000000000..523aea224a --- /dev/null +++ b/preact-minimal/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/minimal' + +export default function App() { + return +} diff --git a/preact-minimal/src/app.css b/preact-minimal/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-minimal/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-minimal/src/components/editor/examples/minimal/editor.tsx b/preact-minimal/src/components/editor/examples/minimal/editor.tsx new file mode 100644 index 0000000000..97bf117796 --- /dev/null +++ b/preact-minimal/src/components/editor/examples/minimal/editor.tsx @@ -0,0 +1,20 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+ ) +} diff --git a/preact-minimal/src/components/editor/examples/minimal/index.ts b/preact-minimal/src/components/editor/examples/minimal/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-minimal/src/components/editor/examples/minimal/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-minimal/src/main.tsx b/preact-minimal/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-minimal/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-minimal/tsconfig.app.json b/preact-minimal/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-minimal/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-minimal/tsconfig.json b/preact-minimal/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-minimal/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-minimal/tsconfig.node.json b/preact-minimal/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-minimal/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-minimal/vite.config.ts b/preact-minimal/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-minimal/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-placeholder/.gitignore b/preact-placeholder/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-placeholder/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-placeholder/README.md b/preact-placeholder/README.md new file mode 100644 index 0000000000..716771bab8 --- /dev/null +++ b/preact-placeholder/README.md @@ -0,0 +1,15 @@ +# preact-placeholder + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-placeholder) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-placeholder) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-placeholder preact-placeholder +cd preact-placeholder +npm install +npm run dev +``` diff --git a/preact-placeholder/index.html b/preact-placeholder/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-placeholder/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-placeholder/package.json b/preact-placeholder/package.json new file mode 100644 index 0000000000..92816586f5 --- /dev/null +++ b/preact-placeholder/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-placeholder", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-placeholder/src/App.tsx b/preact-placeholder/src/App.tsx new file mode 100644 index 0000000000..919da8503a --- /dev/null +++ b/preact-placeholder/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/placeholder' + +export default function App() { + return +} diff --git a/preact-placeholder/src/app.css b/preact-placeholder/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-placeholder/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-placeholder/src/components/editor/examples/placeholder/editor.tsx b/preact-placeholder/src/components/editor/examples/placeholder/editor.tsx new file mode 100644 index 0000000000..28bd4bf9e9 --- /dev/null +++ b/preact-placeholder/src/components/editor/examples/placeholder/editor.tsx @@ -0,0 +1,39 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useCallback, useMemo } from 'preact/hooks' +import { createEditor, jsonFromNode, type NodeJSON } from 'prosekit/core' +import type { ProseMirrorNode } from 'prosekit/pm/model' +import { ProseKit, useDocChange } from 'prosekit/preact' + +import { defineExtension } from './extension' + +export default function Editor(props: { + initialContent?: NodeJSON + onDocUpdate?: (doc: NodeJSON) => void +}) { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent: props.initialContent }) + }, [props.initialContent]) + + const { onDocUpdate } = props + const handleDocChange = useCallback( + (doc: ProseMirrorNode) => onDocUpdate?.(jsonFromNode(doc)), + [onDocUpdate], + ) + useDocChange(handleDocChange, { editor }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/preact-placeholder/src/components/editor/examples/placeholder/extension.ts b/preact-placeholder/src/components/editor/examples/placeholder/extension.ts new file mode 100644 index 0000000000..12d0ba26f4 --- /dev/null +++ b/preact-placeholder/src/components/editor/examples/placeholder/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Type something...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-placeholder/src/components/editor/examples/placeholder/index.ts b/preact-placeholder/src/components/editor/examples/placeholder/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-placeholder/src/components/editor/examples/placeholder/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-placeholder/src/main.tsx b/preact-placeholder/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-placeholder/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-placeholder/tsconfig.app.json b/preact-placeholder/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-placeholder/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-placeholder/tsconfig.json b/preact-placeholder/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-placeholder/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-placeholder/tsconfig.node.json b/preact-placeholder/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-placeholder/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-placeholder/vite.config.ts b/preact-placeholder/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-placeholder/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-readonly/.gitignore b/preact-readonly/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-readonly/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-readonly/README.md b/preact-readonly/README.md new file mode 100644 index 0000000000..ad30c0b214 --- /dev/null +++ b/preact-readonly/README.md @@ -0,0 +1,15 @@ +# preact-readonly + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-readonly) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-readonly) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-readonly preact-readonly +cd preact-readonly +npm install +npm run dev +``` diff --git a/preact-readonly/index.html b/preact-readonly/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-readonly/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-readonly/package.json b/preact-readonly/package.json new file mode 100644 index 0000000000..d556c61138 --- /dev/null +++ b/preact-readonly/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-readonly", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-readonly/src/App.tsx b/preact-readonly/src/App.tsx new file mode 100644 index 0000000000..dc728e840f --- /dev/null +++ b/preact-readonly/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/readonly' + +export default function App() { + return +} diff --git a/preact-readonly/src/app.css b/preact-readonly/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-readonly/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-readonly/src/components/editor/examples/readonly/editor.tsx b/preact-readonly/src/components/editor/examples/readonly/editor.tsx new file mode 100644 index 0000000000..0554371f6f --- /dev/null +++ b/preact-readonly/src/components/editor/examples/readonly/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-readonly' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-readonly/src/components/editor/examples/readonly/extension.ts b/preact-readonly/src/components/editor/examples/readonly/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/preact-readonly/src/components/editor/examples/readonly/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/preact-readonly/src/components/editor/examples/readonly/index.ts b/preact-readonly/src/components/editor/examples/readonly/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-readonly/src/components/editor/examples/readonly/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-readonly/src/components/editor/examples/readonly/toolbar.tsx b/preact-readonly/src/components/editor/examples/readonly/toolbar.tsx new file mode 100644 index 0000000000..9ba96d3459 --- /dev/null +++ b/preact-readonly/src/components/editor/examples/readonly/toolbar.tsx @@ -0,0 +1,19 @@ +import { Button } from '../../ui/button' + +import { useReadonly } from './use-readonly' + +export default function Toolbar() { + const { readonly, setReadonly } = useReadonly() + + return ( +
+ + + +
+ ) +} diff --git a/preact-readonly/src/components/editor/examples/readonly/use-readonly.ts b/preact-readonly/src/components/editor/examples/readonly/use-readonly.ts new file mode 100644 index 0000000000..1b8ba24ebe --- /dev/null +++ b/preact-readonly/src/components/editor/examples/readonly/use-readonly.ts @@ -0,0 +1,14 @@ +import { useMemo, useState } from 'preact/hooks' +import { defineReadonly } from 'prosekit/extensions/readonly' +import { useExtension } from 'prosekit/preact' + +export function useReadonly() { + const [readonly, setReadonly] = useState(true) + + const extension = useMemo(() => { + return readonly ? defineReadonly() : null + }, [readonly]) + useExtension(extension) + + return { readonly, setReadonly } +} diff --git a/preact-readonly/src/components/editor/sample/sample-doc-readonly.ts b/preact-readonly/src/components/editor/sample/sample-doc-readonly.ts new file mode 100644 index 0000000000..abd9e2c6ac --- /dev/null +++ b/preact-readonly/src/components/editor/sample/sample-doc-readonly.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', + }, + ], + }, + ], +} diff --git a/preact-readonly/src/components/editor/ui/button/button.tsx b/preact-readonly/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-readonly/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-readonly/src/components/editor/ui/button/index.ts b/preact-readonly/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-readonly/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-readonly/src/main.tsx b/preact-readonly/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-readonly/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-readonly/tsconfig.app.json b/preact-readonly/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-readonly/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-readonly/tsconfig.json b/preact-readonly/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-readonly/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-readonly/tsconfig.node.json b/preact-readonly/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-readonly/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-readonly/vite.config.ts b/preact-readonly/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-readonly/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-rtl/.gitignore b/preact-rtl/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-rtl/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-rtl/README.md b/preact-rtl/README.md new file mode 100644 index 0000000000..6bdae8c7f1 --- /dev/null +++ b/preact-rtl/README.md @@ -0,0 +1,15 @@ +# preact-rtl + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-rtl) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-rtl) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-rtl preact-rtl +cd preact-rtl +npm install +npm run dev +``` diff --git a/preact-rtl/index.html b/preact-rtl/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-rtl/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-rtl/package.json b/preact-rtl/package.json new file mode 100644 index 0000000000..9e187a1313 --- /dev/null +++ b/preact-rtl/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-rtl", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-rtl/src/App.tsx b/preact-rtl/src/App.tsx new file mode 100644 index 0000000000..b7c8653ece --- /dev/null +++ b/preact-rtl/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/rtl' + +export default function App() { + return +} diff --git a/preact-rtl/src/app.css b/preact-rtl/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-rtl/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-rtl/src/components/editor/examples/rtl/editor.tsx b/preact-rtl/src/components/editor/examples/rtl/editor.tsx new file mode 100644 index 0000000000..7ceb17d06b --- /dev/null +++ b/preact-rtl/src/components/editor/examples/rtl/editor.tsx @@ -0,0 +1,50 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-rtl' +import { sampleUploader } from '../../sample/sample-uploader' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' +import { InlineMenu } from '../../ui/inline-menu' +import { SlashMenu } from '../../ui/slash-menu' +import { TableHandle } from '../../ui/table-handle' +import { Toolbar } from '../../ui/toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+ + + + + +
+
+
+ ) +} diff --git a/preact-rtl/src/components/editor/examples/rtl/index.ts b/preact-rtl/src/components/editor/examples/rtl/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-rtl/src/components/editor/examples/rtl/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-rtl/src/components/editor/sample/sample-doc-rtl.ts b/preact-rtl/src/components/editor/sample/sample-doc-rtl.ts new file mode 100644 index 0000000000..696e797724 --- /dev/null +++ b/preact-rtl/src/components/editor/sample/sample-doc-rtl.ts @@ -0,0 +1,187 @@ +import type { NodeJSON } from 'prosekit/core' + +const translation = { + Paragraph: 'فقرة', + 'Root list item': 'عنصر قائمة جذري', + 'Sub list item': 'عنصر قائمة فرعي', + 'Completed task': 'مهمة مكتملة', + 'Pending task': 'مهمة قيد الانتظار', + Quote: 'اقتباس', +} as const + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Right to Left' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Paragraph'] }], + }, + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Root list item'] }], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Completed task'] }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Pending task'] }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: 'hello world', + }, + ], + }, + + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, + ], + }, + ], + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: translation['Quote'], + }, + ], + }, + ], + }, + ], +} diff --git a/preact-rtl/src/components/editor/sample/sample-uploader.ts b/preact-rtl/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/preact-rtl/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/preact-rtl/src/components/editor/ui/block-handle/block-handle.tsx b/preact-rtl/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..8f5fe62e40 --- /dev/null +++ b/preact-rtl/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,31 @@ +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/preact/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/preact-rtl/src/components/editor/ui/block-handle/index.ts b/preact-rtl/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/preact-rtl/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/preact-rtl/src/components/editor/ui/button/button.tsx b/preact-rtl/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-rtl/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-rtl/src/components/editor/ui/button/index.ts b/preact-rtl/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-rtl/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/preact-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx new file mode 100644 index 0000000000..6ace546a12 --- /dev/null +++ b/preact-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx @@ -0,0 +1,5 @@ +import { DropIndicator as BaseDropIndicator } from 'prosekit/preact/drop-indicator' + +export default function DropIndicator() { + return +} diff --git a/preact-rtl/src/components/editor/ui/drop-indicator/index.ts b/preact-rtl/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..f8fb7139c4 --- /dev/null +++ b/preact-rtl/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator' diff --git a/preact-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-rtl/src/components/editor/ui/image-upload-popover/index.ts b/preact-rtl/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-rtl/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-rtl/src/components/editor/ui/inline-menu/index.ts b/preact-rtl/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/preact-rtl/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/preact-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..a014b74f57 --- /dev/null +++ b/preact-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +import type { JSX } from 'preact' +import { useState } from 'preact/hooks' +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/preact' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/preact/inline-popover' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + const handleSubmit = ( + event: JSX.TargetedEvent, + ) => { + event.preventDefault() + const href = event.currentTarget.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
+ +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/preact-rtl/src/components/editor/ui/slash-menu/index.ts b/preact-rtl/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/preact-rtl/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..bedf7d7ebb --- /dev/null +++ b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,9 @@ +import { AutocompleteEmpty } from 'prosekit/preact/autocomplete' + +export default function SlashMenuEmpty() { + return ( + + No results + + ) +} diff --git a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..1bb81f797d --- /dev/null +++ b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,21 @@ +import { AutocompleteItem } from 'prosekit/preact/autocomplete' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}) { + return ( + + {props.label} + {props.kbd && ( + + {props.kbd} + + )} + + ) +} diff --git a/preact-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..092327c28e --- /dev/null +++ b/preact-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,100 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/preact' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/preact/autocomplete' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor.commands.setParagraph()} + /> + + editor.commands.setHeading({ level: 1 })} + /> + + editor.commands.setHeading({ level: 2 })} + /> + + editor.commands.setHeading({ level: 3 })} + /> + + editor.commands.wrapInList({ kind: 'bullet' })} + /> + + editor.commands.wrapInList({ kind: 'ordered' })} + /> + + editor.commands.wrapInList({ kind: 'task' })} + /> + + editor.commands.wrapInList({ kind: 'toggle' })} + /> + + editor.commands.setBlockquote()} + /> + + editor.commands.insertTable({ row: 3, col: 3 })} + /> + + editor.commands.insertHorizontalRule()} + /> + + editor.commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/preact-rtl/src/components/editor/ui/table-handle/index.ts b/preact-rtl/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/preact-rtl/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/preact-rtl/src/components/editor/ui/table-handle/table-handle.tsx b/preact-rtl/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..6182b185c6 --- /dev/null +++ b/preact-rtl/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,186 @@ +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/preact' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/preact/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/preact/table-handle' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props) { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + {state.addTableColumnBefore.canExec && ( + + Insert Left + + )} + {state.addTableColumnAfter.canExec && ( + + Insert Right + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableColumn.canExec && ( + + Delete Column + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+ + + + +
+
+ + + {state.addTableRowAbove.canExec && ( + + Insert Above + + )} + {state.addTableRowBelow.canExec && ( + + Insert Below + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableRow.canExec && ( + + Delete Row + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+
+ ) +} diff --git a/preact-rtl/src/components/editor/ui/toolbar/index.ts b/preact-rtl/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-rtl/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-rtl/src/components/editor/ui/toolbar/toolbar.tsx b/preact-rtl/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-rtl/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-rtl/src/main.tsx b/preact-rtl/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-rtl/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-rtl/tsconfig.app.json b/preact-rtl/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-rtl/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-rtl/tsconfig.json b/preact-rtl/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-rtl/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-rtl/tsconfig.node.json b/preact-rtl/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-rtl/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-rtl/vite.config.ts b/preact-rtl/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-rtl/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-save-html/.gitignore b/preact-save-html/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-save-html/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-save-html/README.md b/preact-save-html/README.md new file mode 100644 index 0000000000..329319f3aa --- /dev/null +++ b/preact-save-html/README.md @@ -0,0 +1,15 @@ +# preact-save-html + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-save-html) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-save-html) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-save-html preact-save-html +cd preact-save-html +npm install +npm run dev +``` diff --git a/preact-save-html/index.html b/preact-save-html/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-save-html/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-save-html/package.json b/preact-save-html/package.json new file mode 100644 index 0000000000..3aff0753f4 --- /dev/null +++ b/preact-save-html/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-save-html", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-save-html/src/App.tsx b/preact-save-html/src/App.tsx new file mode 100644 index 0000000000..cd1a678bb6 --- /dev/null +++ b/preact-save-html/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-html' + +export default function App() { + return +} diff --git a/preact-save-html/src/app.css b/preact-save-html/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-save-html/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-save-html/src/components/editor/examples/save-html/editor.tsx b/preact-save-html/src/components/editor/examples/save-html/editor.tsx new file mode 100644 index 0000000000..94b40c24e8 --- /dev/null +++ b/preact-save-html/src/components/editor/examples/save-html/editor.tsx @@ -0,0 +1,74 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useCallback, useMemo, useState } from 'preact/hooks' +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, jsonFromHTML } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/preact' + +export default function Editor() { + // A list of saved documents, stored as HTML strings + const [records, setRecords] = useState([]) + // Whether there are unsaved changes + const [hasUnsavedChange, setHasUnsavedChange] = useState(false) + // A key to force a re-render of the editor + const [key, setKey] = useState(1) + + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension }) + }, []) + + const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) + useDocChange(handleDocChange, { editor }) + + const handleSave = useCallback(() => { + const record = editor.getDocHTML() + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + }, [editor]) + + const handleLoad = useCallback( + (record: string) => { + editor.setContent(jsonFromHTML(record, { schema: editor.schema })) + setHasUnsavedChange(false) + setKey((prev) => prev + 1) + }, + [editor], + ) + + return ( +
+ +
    + {records.map((record, index) => ( +
  • + + +
    {record}
    +
    +
  • + ))} +
+ +
+
+
+
+
+ ) +} diff --git a/preact-save-html/src/components/editor/examples/save-html/index.ts b/preact-save-html/src/components/editor/examples/save-html/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-save-html/src/components/editor/examples/save-html/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-save-html/src/main.tsx b/preact-save-html/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-save-html/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-save-html/tsconfig.app.json b/preact-save-html/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-save-html/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-save-html/tsconfig.json b/preact-save-html/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-save-html/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-save-html/tsconfig.node.json b/preact-save-html/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-save-html/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-save-html/vite.config.ts b/preact-save-html/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-save-html/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-save-json/.gitignore b/preact-save-json/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-save-json/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-save-json/README.md b/preact-save-json/README.md new file mode 100644 index 0000000000..b3d34b02e3 --- /dev/null +++ b/preact-save-json/README.md @@ -0,0 +1,15 @@ +# preact-save-json + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-save-json) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-save-json) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-save-json preact-save-json +cd preact-save-json +npm install +npm run dev +``` diff --git a/preact-save-json/index.html b/preact-save-json/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-save-json/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-save-json/package.json b/preact-save-json/package.json new file mode 100644 index 0000000000..9ed2eb08a3 --- /dev/null +++ b/preact-save-json/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-save-json", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-save-json/src/App.tsx b/preact-save-json/src/App.tsx new file mode 100644 index 0000000000..c35583f0b4 --- /dev/null +++ b/preact-save-json/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-json' + +export default function App() { + return +} diff --git a/preact-save-json/src/app.css b/preact-save-json/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-save-json/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-save-json/src/components/editor/examples/save-json/editor.tsx b/preact-save-json/src/components/editor/examples/save-json/editor.tsx new file mode 100644 index 0000000000..c6028ac7a4 --- /dev/null +++ b/preact-save-json/src/components/editor/examples/save-json/editor.tsx @@ -0,0 +1,74 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useCallback, useMemo, useState } from 'preact/hooks' +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/preact' + +export default function Editor() { + // A list of saved documents, stored as JSON strings + const [records, setRecords] = useState([]) + // Whether there are unsaved changes + const [hasUnsavedChange, setHasUnsavedChange] = useState(false) + // A key to force a re-render of the editor + const [key, setKey] = useState(1) + + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension }) + }, []) + + const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) + useDocChange(handleDocChange, { editor }) + + const handleSave = useCallback(() => { + const record = JSON.stringify(editor.getDocJSON()) + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + }, [editor]) + + const handleLoad = useCallback( + (record: string) => { + editor.setContent(JSON.parse(record) as NodeJSON) + setHasUnsavedChange(false) + setKey((prev) => prev + 1) + }, + [editor], + ) + + return ( +
+ +
    + {records.map((record, index) => ( +
  • + + +
    {record}
    +
    +
  • + ))} +
+ +
+
+
+
+
+ ) +} diff --git a/preact-save-json/src/components/editor/examples/save-json/index.ts b/preact-save-json/src/components/editor/examples/save-json/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-save-json/src/components/editor/examples/save-json/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-save-json/src/main.tsx b/preact-save-json/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-save-json/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-save-json/tsconfig.app.json b/preact-save-json/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-save-json/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-save-json/tsconfig.json b/preact-save-json/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-save-json/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-save-json/tsconfig.node.json b/preact-save-json/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-save-json/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-save-json/vite.config.ts b/preact-save-json/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-save-json/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-save-markdown/.gitignore b/preact-save-markdown/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-save-markdown/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-save-markdown/README.md b/preact-save-markdown/README.md new file mode 100644 index 0000000000..d5c4ab6272 --- /dev/null +++ b/preact-save-markdown/README.md @@ -0,0 +1,15 @@ +# preact-save-markdown + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-save-markdown) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-save-markdown) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-save-markdown preact-save-markdown +cd preact-save-markdown +npm install +npm run dev +``` diff --git a/preact-save-markdown/index.html b/preact-save-markdown/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-save-markdown/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-save-markdown/package.json b/preact-save-markdown/package.json new file mode 100644 index 0000000000..3f31b27efc --- /dev/null +++ b/preact-save-markdown/package.json @@ -0,0 +1,32 @@ +{ + "name": "example-preact-save-markdown", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0", + "rehype-parse": "^9.0.1", + "rehype-remark": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-html": "^16.0.1", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.5" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-save-markdown/src/App.tsx b/preact-save-markdown/src/App.tsx new file mode 100644 index 0000000000..776d1fdf5b --- /dev/null +++ b/preact-save-markdown/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-markdown' + +export default function App() { + return +} diff --git a/preact-save-markdown/src/app.css b/preact-save-markdown/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-save-markdown/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-save-markdown/src/components/editor/examples/save-markdown/editor.tsx b/preact-save-markdown/src/components/editor/examples/save-markdown/editor.tsx new file mode 100644 index 0000000000..06a52923f5 --- /dev/null +++ b/preact-save-markdown/src/components/editor/examples/save-markdown/editor.tsx @@ -0,0 +1,78 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useCallback, useMemo, useState } from 'preact/hooks' +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, jsonFromHTML } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/preact' + +import { htmlFromMarkdown, markdownFromHTML } from './markdown' + +export default function Editor() { + // A list of saved documents, stored as Markdown strings + const [records, setRecords] = useState([]) + // Whether there are unsaved changes + const [hasUnsavedChange, setHasUnsavedChange] = useState(false) + // A key to force a re-render of the editor + const [key, setKey] = useState(1) + + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension }) + }, []) + + const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) + useDocChange(handleDocChange, { editor }) + + const handleSave = useCallback(() => { + const html = editor.getDocHTML() + const record = markdownFromHTML(html) + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + }, [editor]) + + const handleLoad = useCallback( + (record: string) => { + const html = htmlFromMarkdown(record) + editor.setContent(jsonFromHTML(html, { schema: editor.schema })) + setHasUnsavedChange(false) + setKey((prev) => prev + 1) + }, + [editor], + ) + + return ( +
+ +
    + {records.map((record, index) => ( +
  • + + +
    {record}
    +
    +
  • + ))} +
+ +
+
+
+
+
+ ) +} diff --git a/preact-save-markdown/src/components/editor/examples/save-markdown/index.ts b/preact-save-markdown/src/components/editor/examples/save-markdown/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-save-markdown/src/components/editor/examples/save-markdown/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/preact-save-markdown/src/components/editor/examples/save-markdown/markdown.ts new file mode 100644 index 0000000000..3f930adad2 --- /dev/null +++ b/preact-save-markdown/src/components/editor/examples/save-markdown/markdown.ts @@ -0,0 +1,26 @@ +import rehypeParse from 'rehype-parse' +import rehypeRemark from 'rehype-remark' +import remarkGfm from 'remark-gfm' +import remarkHtml from 'remark-html' +import remarkParse from 'remark-parse' +import remarkStringify from 'remark-stringify' +import { unified } from 'unified' + +export function markdownFromHTML(html: string): string { + return unified() + .use(rehypeParse) + .use(rehypeRemark) + .use(remarkGfm) + .use(remarkStringify) + .processSync(html) + .toString() +} + +export function htmlFromMarkdown(markdown: string): string { + return unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkHtml) + .processSync(markdown) + .toString() +} diff --git a/preact-save-markdown/src/main.tsx b/preact-save-markdown/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-save-markdown/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-save-markdown/tsconfig.app.json b/preact-save-markdown/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-save-markdown/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-save-markdown/tsconfig.json b/preact-save-markdown/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-save-markdown/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-save-markdown/tsconfig.node.json b/preact-save-markdown/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-save-markdown/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-save-markdown/vite.config.ts b/preact-save-markdown/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-save-markdown/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-search/.gitignore b/preact-search/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-search/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-search/README.md b/preact-search/README.md new file mode 100644 index 0000000000..b854505b4d --- /dev/null +++ b/preact-search/README.md @@ -0,0 +1,15 @@ +# preact-search + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-search) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-search) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-search preact-search +cd preact-search +npm install +npm run dev +``` diff --git a/preact-search/index.html b/preact-search/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-search/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-search/package.json b/preact-search/package.json new file mode 100644 index 0000000000..b797dda6b4 --- /dev/null +++ b/preact-search/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-search", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-search/src/App.tsx b/preact-search/src/App.tsx new file mode 100644 index 0000000000..2f6b77056f --- /dev/null +++ b/preact-search/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/search' + +export default function App() { + return +} diff --git a/preact-search/src/app.css b/preact-search/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-search/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-search/src/components/editor/examples/search/editor.tsx b/preact-search/src/components/editor/examples/search/editor.tsx new file mode 100644 index 0000000000..29f4e7ce4b --- /dev/null +++ b/preact-search/src/components/editor/examples/search/editor.tsx @@ -0,0 +1,41 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/search/style.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-search' +import { Search } from '../../ui/search' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ + extension, + defaultContent, + }) + }, [defaultContent]) + + return ( + +
+
+ +
+
+
+
+ ) +} diff --git a/preact-search/src/components/editor/examples/search/extension.ts b/preact-search/src/components/editor/examples/search/extension.ts new file mode 100644 index 0000000000..10ff13f614 --- /dev/null +++ b/preact-search/src/components/editor/examples/search/extension.ts @@ -0,0 +1,9 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineSearchCommands } from 'prosekit/extensions/search' + +export function defineExtension() { + return union(defineBasicExtension(), defineSearchCommands()) +} + +export type EditorExtension = ReturnType diff --git a/preact-search/src/components/editor/examples/search/index.ts b/preact-search/src/components/editor/examples/search/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-search/src/components/editor/examples/search/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-search/src/components/editor/sample/sample-doc-search.ts b/preact-search/src/components/editor/sample/sample-doc-search.ts new file mode 100644 index 0000000000..c8160cca2a --- /dev/null +++ b/preact-search/src/components/editor/sample/sample-doc-search.ts @@ -0,0 +1,79 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Baa, baa, black sheep,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Have you any wool?', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Yes, sir, yes, sir,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Three bags full;', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'One for the master,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the dame,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the little boy', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Who lives down the lane.', + }, + ], + }, + ], +} diff --git a/preact-search/src/components/editor/ui/button/button.tsx b/preact-search/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-search/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-search/src/components/editor/ui/button/index.ts b/preact-search/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-search/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-search/src/components/editor/ui/search/index.ts b/preact-search/src/components/editor/ui/search/index.ts new file mode 100644 index 0000000000..0a1f03c720 --- /dev/null +++ b/preact-search/src/components/editor/ui/search/index.ts @@ -0,0 +1 @@ +export { default as Search } from './search' diff --git a/preact-search/src/components/editor/ui/search/search.tsx b/preact-search/src/components/editor/ui/search/search.tsx new file mode 100644 index 0000000000..e8f88802a9 --- /dev/null +++ b/preact-search/src/components/editor/ui/search/search.tsx @@ -0,0 +1,167 @@ +import { useMemo, useState } from 'preact/hooks' +import { + defineSearchQuery, + type SearchCommandsExtension, +} from 'prosekit/extensions/search' +import { useEditor, useExtension } from 'prosekit/preact' + +import { Button } from '../button' + +export default function Search(props: { onClose?: VoidFunction }) { + const [showReplace, setShowReplace] = useState(false) + const toggleReplace = () => setShowReplace((value) => !value) + + const [searchText, setSearchText] = useState('') + const [replaceText, setReplaceText] = useState('') + const [caseSensitive, setCaseSensitive] = useState(false) + const [wholeWord, setWholeWord] = useState(false) + const [regexp, setRegexp] = useState(false) + const [literal, setLiteral] = useState(false) + + const extension = useMemo(() => { + if (!searchText) { + return null + } + return defineSearchQuery({ + search: searchText, + replace: replaceText, + caseSensitive, + wholeWord, + regexp, + literal, + }) + }, [searchText, replaceText, caseSensitive, wholeWord, regexp, literal]) + + useExtension(extension) + + const editor = useEditor() + + const handleSearchKeyDown = (event: KeyboardEvent) => { + if (isEnter(event)) { + event.preventDefault() + editor.commands.findNext() + } else if (isShiftEnter(event)) { + event.preventDefault() + editor.commands.findPrev() + } + } + + const handleReplaceKeyDown = (event: KeyboardEvent) => { + if (isEnter(event)) { + event.preventDefault() + editor.commands.replaceNext() + } else if (isShiftEnter(event)) { + event.preventDefault() + editor.commands.replaceAll() + } + } + + return ( +
+ + setSearchText(event.currentTarget.value)} + onKeyDown={handleSearchKeyDown} + className="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" + /> +
+ + + + + + + +
+ {showReplace && ( + setReplaceText(event.currentTarget.value)} + onKeyDown={handleReplaceKeyDown} + className="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" + /> + )} + {showReplace && ( +
+ + +
+ )} +
+ ) +} + +function isEnter(event: KeyboardEvent) { + return ( + event.key === 'Enter' && + !event.shiftKey && + !event.metaKey && + !event.altKey && + !event.ctrlKey && + !event.isComposing + ) +} + +function isShiftEnter(event: KeyboardEvent) { + return ( + event.key === 'Enter' && + event.shiftKey && + !event.metaKey && + !event.altKey && + !event.ctrlKey && + !event.isComposing + ) +} diff --git a/preact-search/src/main.tsx b/preact-search/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-search/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-search/tsconfig.app.json b/preact-search/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-search/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-search/tsconfig.json b/preact-search/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-search/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-search/tsconfig.node.json b/preact-search/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-search/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-search/vite.config.ts b/preact-search/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-search/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-slash-menu/.gitignore b/preact-slash-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-slash-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-slash-menu/README.md b/preact-slash-menu/README.md new file mode 100644 index 0000000000..aecb620e7b --- /dev/null +++ b/preact-slash-menu/README.md @@ -0,0 +1,15 @@ +# preact-slash-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-slash-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-slash-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-slash-menu preact-slash-menu +cd preact-slash-menu +npm install +npm run dev +``` diff --git a/preact-slash-menu/index.html b/preact-slash-menu/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-slash-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-slash-menu/package.json b/preact-slash-menu/package.json new file mode 100644 index 0000000000..2092e82a7c --- /dev/null +++ b/preact-slash-menu/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-slash-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-slash-menu/src/App.tsx b/preact-slash-menu/src/App.tsx new file mode 100644 index 0000000000..cf430661be --- /dev/null +++ b/preact-slash-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/slash-menu' + +export default function App() { + return +} diff --git a/preact-slash-menu/src/app.css b/preact-slash-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-slash-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-slash-menu/src/components/editor/examples/slash-menu/editor.tsx b/preact-slash-menu/src/components/editor/examples/slash-menu/editor.tsx new file mode 100644 index 0000000000..ddfc10b34a --- /dev/null +++ b/preact-slash-menu/src/components/editor/examples/slash-menu/editor.tsx @@ -0,0 +1,31 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { SlashMenu } from '../../ui/slash-menu' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/preact-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/preact-slash-menu/src/components/editor/examples/slash-menu/extension.ts new file mode 100644 index 0000000000..0edda60136 --- /dev/null +++ b/preact-slash-menu/src/components/editor/examples/slash-menu/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-slash-menu/src/components/editor/examples/slash-menu/index.ts b/preact-slash-menu/src/components/editor/examples/slash-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-slash-menu/src/components/editor/examples/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-slash-menu/src/components/editor/ui/slash-menu/index.ts b/preact-slash-menu/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/preact-slash-menu/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..bedf7d7ebb --- /dev/null +++ b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,9 @@ +import { AutocompleteEmpty } from 'prosekit/preact/autocomplete' + +export default function SlashMenuEmpty() { + return ( + + No results + + ) +} diff --git a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..1bb81f797d --- /dev/null +++ b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,21 @@ +import { AutocompleteItem } from 'prosekit/preact/autocomplete' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}) { + return ( + + {props.label} + {props.kbd && ( + + {props.kbd} + + )} + + ) +} diff --git a/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..092327c28e --- /dev/null +++ b/preact-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,100 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/preact' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/preact/autocomplete' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor.commands.setParagraph()} + /> + + editor.commands.setHeading({ level: 1 })} + /> + + editor.commands.setHeading({ level: 2 })} + /> + + editor.commands.setHeading({ level: 3 })} + /> + + editor.commands.wrapInList({ kind: 'bullet' })} + /> + + editor.commands.wrapInList({ kind: 'ordered' })} + /> + + editor.commands.wrapInList({ kind: 'task' })} + /> + + editor.commands.wrapInList({ kind: 'toggle' })} + /> + + editor.commands.setBlockquote()} + /> + + editor.commands.insertTable({ row: 3, col: 3 })} + /> + + editor.commands.insertHorizontalRule()} + /> + + editor.commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/preact-slash-menu/src/main.tsx b/preact-slash-menu/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-slash-menu/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-slash-menu/tsconfig.app.json b/preact-slash-menu/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-slash-menu/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-slash-menu/tsconfig.json b/preact-slash-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-slash-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-slash-menu/tsconfig.node.json b/preact-slash-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-slash-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-slash-menu/vite.config.ts b/preact-slash-menu/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-slash-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-strike/.gitignore b/preact-strike/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-strike/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-strike/README.md b/preact-strike/README.md new file mode 100644 index 0000000000..3ae1aaa017 --- /dev/null +++ b/preact-strike/README.md @@ -0,0 +1,15 @@ +# preact-strike + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-strike) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-strike) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-strike preact-strike +cd preact-strike +npm install +npm run dev +``` diff --git a/preact-strike/index.html b/preact-strike/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-strike/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-strike/package.json b/preact-strike/package.json new file mode 100644 index 0000000000..c2028d282f --- /dev/null +++ b/preact-strike/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-strike", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-strike/src/App.tsx b/preact-strike/src/App.tsx new file mode 100644 index 0000000000..497a57c0d8 --- /dev/null +++ b/preact-strike/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/strike' + +export default function App() { + return +} diff --git a/preact-strike/src/app.css b/preact-strike/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-strike/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-strike/src/components/editor/examples/strike/editor.tsx b/preact-strike/src/components/editor/examples/strike/editor.tsx new file mode 100644 index 0000000000..f9580e6f44 --- /dev/null +++ b/preact-strike/src/components/editor/examples/strike/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-strike' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-strike/src/components/editor/examples/strike/extension.ts b/preact-strike/src/components/editor/examples/strike/extension.ts new file mode 100644 index 0000000000..c013303ccc --- /dev/null +++ b/preact-strike/src/components/editor/examples/strike/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineStrike(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-strike/src/components/editor/examples/strike/index.ts b/preact-strike/src/components/editor/examples/strike/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-strike/src/components/editor/examples/strike/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-strike/src/components/editor/examples/strike/toolbar.tsx b/preact-strike/src/components/editor/examples/strike/toolbar.tsx new file mode 100644 index 0000000000..3566b6c801 --- /dev/null +++ b/preact-strike/src/components/editor/examples/strike/toolbar.tsx @@ -0,0 +1,32 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + strike: { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/preact-strike/src/components/editor/sample/sample-doc-strike.ts b/preact-strike/src/components/editor/sample/sample-doc-strike.ts new file mode 100644 index 0000000000..2e025e9b02 --- /dev/null +++ b/preact-strike/src/components/editor/sample/sample-doc-strike.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'This is strike', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/preact-strike/src/components/editor/ui/button/button.tsx b/preact-strike/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-strike/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-strike/src/components/editor/ui/button/index.ts b/preact-strike/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-strike/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-strike/src/main.tsx b/preact-strike/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-strike/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-strike/tsconfig.app.json b/preact-strike/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-strike/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-strike/tsconfig.json b/preact-strike/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-strike/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-strike/tsconfig.node.json b/preact-strike/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-strike/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-strike/vite.config.ts b/preact-strike/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-strike/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-sub-sup/.gitignore b/preact-sub-sup/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-sub-sup/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-sub-sup/README.md b/preact-sub-sup/README.md new file mode 100644 index 0000000000..df69875b3b --- /dev/null +++ b/preact-sub-sup/README.md @@ -0,0 +1,15 @@ +# preact-sub-sup + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-sub-sup) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-sub-sup) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-sub-sup preact-sub-sup +cd preact-sub-sup +npm install +npm run dev +``` diff --git a/preact-sub-sup/index.html b/preact-sub-sup/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-sub-sup/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-sub-sup/package.json b/preact-sub-sup/package.json new file mode 100644 index 0000000000..76fd495fa3 --- /dev/null +++ b/preact-sub-sup/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-sub-sup", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-sub-sup/src/App.tsx b/preact-sub-sup/src/App.tsx new file mode 100644 index 0000000000..48e43d6423 --- /dev/null +++ b/preact-sub-sup/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/sub-sup' + +export default function App() { + return +} diff --git a/preact-sub-sup/src/app.css b/preact-sub-sup/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-sub-sup/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-sub-sup/src/components/editor/examples/sub-sup/editor.tsx b/preact-sub-sup/src/components/editor/examples/sub-sup/editor.tsx new file mode 100644 index 0000000000..6f37abd3c9 --- /dev/null +++ b/preact-sub-sup/src/components/editor/examples/sub-sup/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-sub-sup' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/preact-sub-sup/src/components/editor/examples/sub-sup/extension.ts new file mode 100644 index 0000000000..bd67245f86 --- /dev/null +++ b/preact-sub-sup/src/components/editor/examples/sub-sup/extension.ts @@ -0,0 +1,32 @@ +import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineMarkInputRule } from 'prosekit/extensions/input-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineSubscript } from 'prosekit/extensions/subscript' +import { defineSuperscript } from 'prosekit/extensions/superscript' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineSubscript(), + defineSuperscript(), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ + : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, + type: 'subscript', + }), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ + : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, + type: 'superscript', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-sub-sup/src/components/editor/examples/sub-sup/index.ts b/preact-sub-sup/src/components/editor/examples/sub-sup/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-sub-sup/src/components/editor/examples/sub-sup/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx b/preact-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx new file mode 100644 index 0000000000..e62a1556b8 --- /dev/null +++ b/preact-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx @@ -0,0 +1,44 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + subscript: { + isActive: editor.marks.subscript.isActive(), + canExec: editor.commands.toggleSubscript.canExec(), + command: () => editor.commands.toggleSubscript(), + }, + superscript: { + isActive: editor.marks.superscript.isActive(), + canExec: editor.commands.toggleSuperscript.canExec(), + command: () => editor.commands.toggleSuperscript(), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + +
+ ) +} diff --git a/preact-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/preact-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts new file mode 100644 index 0000000000..011be750dc --- /dev/null +++ b/preact-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts @@ -0,0 +1,42 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'H', + }, + { + type: 'text', + marks: [ + { + type: 'subscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: 'O is water. x', + }, + { + type: 'text', + marks: [ + { + type: 'superscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: ' is a square.', + }, + ], + }, + ], +} diff --git a/preact-sub-sup/src/components/editor/ui/button/button.tsx b/preact-sub-sup/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-sub-sup/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-sub-sup/src/components/editor/ui/button/index.ts b/preact-sub-sup/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-sub-sup/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-sub-sup/src/main.tsx b/preact-sub-sup/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-sub-sup/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-sub-sup/tsconfig.app.json b/preact-sub-sup/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-sub-sup/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-sub-sup/tsconfig.json b/preact-sub-sup/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-sub-sup/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-sub-sup/tsconfig.node.json b/preact-sub-sup/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-sub-sup/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-sub-sup/vite.config.ts b/preact-sub-sup/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-sub-sup/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-table/.gitignore b/preact-table/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-table/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-table/README.md b/preact-table/README.md new file mode 100644 index 0000000000..bfb4949a6c --- /dev/null +++ b/preact-table/README.md @@ -0,0 +1,15 @@ +# preact-table + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-table) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-table) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-table preact-table +cd preact-table +npm install +npm run dev +``` diff --git a/preact-table/index.html b/preact-table/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-table/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-table/package.json b/preact-table/package.json new file mode 100644 index 0000000000..2d065dacc1 --- /dev/null +++ b/preact-table/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-table", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-table/src/App.tsx b/preact-table/src/App.tsx new file mode 100644 index 0000000000..9d9d957adb --- /dev/null +++ b/preact-table/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/table' + +export default function App() { + return +} diff --git a/preact-table/src/app.css b/preact-table/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-table/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-table/src/components/editor/examples/table/editor.tsx b/preact-table/src/components/editor/examples/table/editor.tsx new file mode 100644 index 0000000000..91d033b947 --- /dev/null +++ b/preact-table/src/components/editor/examples/table/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-table' +import { TableHandle } from '../../ui/table-handle' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/preact-table/src/components/editor/examples/table/extension.ts b/preact-table/src/components/editor/examples/table/extension.ts new file mode 100644 index 0000000000..ee7b142041 --- /dev/null +++ b/preact-table/src/components/editor/examples/table/extension.ts @@ -0,0 +1,20 @@ +import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineTable(), + defineHistory(), + defineGapCursor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-table/src/components/editor/examples/table/index.ts b/preact-table/src/components/editor/examples/table/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-table/src/components/editor/examples/table/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-table/src/components/editor/sample/sample-doc-table.ts b/preact-table/src/components/editor/sample/sample-doc-table.ts new file mode 100644 index 0000000000..c737121672 --- /dev/null +++ b/preact-table/src/components/editor/sample/sample-doc-table.ts @@ -0,0 +1,174 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D1', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D2', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], +} diff --git a/preact-table/src/components/editor/ui/table-handle/index.ts b/preact-table/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/preact-table/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/preact-table/src/components/editor/ui/table-handle/table-handle.tsx b/preact-table/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..6182b185c6 --- /dev/null +++ b/preact-table/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,186 @@ +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/preact' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/preact/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/preact/table-handle' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props) { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + {state.addTableColumnBefore.canExec && ( + + Insert Left + + )} + {state.addTableColumnAfter.canExec && ( + + Insert Right + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableColumn.canExec && ( + + Delete Column + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+ + + + +
+
+ + + {state.addTableRowAbove.canExec && ( + + Insert Above + + )} + {state.addTableRowBelow.canExec && ( + + Insert Below + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableRow.canExec && ( + + Delete Row + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+
+ ) +} diff --git a/preact-table/src/main.tsx b/preact-table/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-table/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-table/tsconfig.app.json b/preact-table/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-table/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-table/tsconfig.json b/preact-table/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-table/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-table/tsconfig.node.json b/preact-table/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-table/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-table/vite.config.ts b/preact-table/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-table/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-text-align/.gitignore b/preact-text-align/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-text-align/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-text-align/README.md b/preact-text-align/README.md new file mode 100644 index 0000000000..0f3b1a6c0c --- /dev/null +++ b/preact-text-align/README.md @@ -0,0 +1,15 @@ +# preact-text-align + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-text-align) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-text-align) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-text-align preact-text-align +cd preact-text-align +npm install +npm run dev +``` diff --git a/preact-text-align/index.html b/preact-text-align/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-text-align/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-text-align/package.json b/preact-text-align/package.json new file mode 100644 index 0000000000..976daaa4a3 --- /dev/null +++ b/preact-text-align/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-text-align", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-text-align/src/App.tsx b/preact-text-align/src/App.tsx new file mode 100644 index 0000000000..0c049df602 --- /dev/null +++ b/preact-text-align/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/text-align' + +export default function App() { + return +} diff --git a/preact-text-align/src/app.css b/preact-text-align/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-text-align/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-text-align/src/components/editor/examples/text-align/editor.tsx b/preact-text-align/src/components/editor/examples/text-align/editor.tsx new file mode 100644 index 0000000000..083edee6f3 --- /dev/null +++ b/preact-text-align/src/components/editor/examples/text-align/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-text-align' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-text-align/src/components/editor/examples/text-align/extension.ts b/preact-text-align/src/components/editor/examples/text-align/extension.ts new file mode 100644 index 0000000000..f1ae44dc7c --- /dev/null +++ b/preact-text-align/src/components/editor/examples/text-align/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineTextAlign } from 'prosekit/extensions/text-align' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextAlign({ types: ['paragraph', 'heading'] }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-text-align/src/components/editor/examples/text-align/index.ts b/preact-text-align/src/components/editor/examples/text-align/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-text-align/src/components/editor/examples/text-align/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-text-align/src/components/editor/examples/text-align/toolbar.tsx b/preact-text-align/src/components/editor/examples/text-align/toolbar.tsx new file mode 100644 index 0000000000..c5daf12c81 --- /dev/null +++ b/preact-text-align/src/components/editor/examples/text-align/toolbar.tsx @@ -0,0 +1,78 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function isTextAlignActive(editor: Editor, value: string) { + return Object.values(editor.nodes).some((node) => { + // @ts-expect-error textAlign may not be available on every node + return node.isActive({ textAlign: value }) + }) +} + +function getToolbarItems(editor: Editor) { + return { + left: { + isActive: isTextAlignActive(editor, 'left'), + canExec: editor.commands.setTextAlign.canExec('left'), + command: () => editor.commands.setTextAlign('left'), + }, + center: { + isActive: isTextAlignActive(editor, 'center'), + canExec: editor.commands.setTextAlign.canExec('center'), + command: () => editor.commands.setTextAlign('center'), + }, + right: { + isActive: isTextAlignActive(editor, 'right'), + canExec: editor.commands.setTextAlign.canExec('right'), + command: () => editor.commands.setTextAlign('right'), + }, + justify: { + isActive: isTextAlignActive(editor, 'justify'), + canExec: editor.commands.setTextAlign.canExec('justify'), + command: () => editor.commands.setTextAlign('justify'), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + + + + + + +
+ ) +} diff --git a/preact-text-align/src/components/editor/sample/sample-doc-text-align.ts b/preact-text-align/src/components/editor/sample/sample-doc-text-align.ts new file mode 100644 index 0000000000..0724cea4f7 --- /dev/null +++ b/preact-text-align/src/components/editor/sample/sample-doc-text-align.ts @@ -0,0 +1,56 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Heading', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'left', + }, + content: [ + { + type: 'text', + text: 'First paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Second paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'right', + }, + content: [ + { + type: 'text', + text: 'Third paragraph', + }, + ], + }, + ], +} diff --git a/preact-text-align/src/components/editor/ui/button/button.tsx b/preact-text-align/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-text-align/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-text-align/src/components/editor/ui/button/index.ts b/preact-text-align/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-text-align/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-text-align/src/main.tsx b/preact-text-align/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-text-align/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-text-align/tsconfig.app.json b/preact-text-align/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-text-align/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-text-align/tsconfig.json b/preact-text-align/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-text-align/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-text-align/tsconfig.node.json b/preact-text-align/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-text-align/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-text-align/vite.config.ts b/preact-text-align/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-text-align/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-text-color/.gitignore b/preact-text-color/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-text-color/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-text-color/README.md b/preact-text-color/README.md new file mode 100644 index 0000000000..fd51bf8cdb --- /dev/null +++ b/preact-text-color/README.md @@ -0,0 +1,15 @@ +# preact-text-color + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-text-color) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-text-color) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-text-color preact-text-color +cd preact-text-color +npm install +npm run dev +``` diff --git a/preact-text-color/index.html b/preact-text-color/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-text-color/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-text-color/package.json b/preact-text-color/package.json new file mode 100644 index 0000000000..e8f702a16d --- /dev/null +++ b/preact-text-color/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-text-color", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-text-color/src/App.tsx b/preact-text-color/src/App.tsx new file mode 100644 index 0000000000..1225de322a --- /dev/null +++ b/preact-text-color/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/text-color' + +export default function App() { + return +} diff --git a/preact-text-color/src/app.css b/preact-text-color/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-text-color/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-text-color/src/components/editor/examples/text-color/editor.tsx b/preact-text-color/src/components/editor/examples/text-color/editor.tsx new file mode 100644 index 0000000000..a3e980832a --- /dev/null +++ b/preact-text-color/src/components/editor/examples/text-color/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-text-color' + +import { defineExtension } from './extension' +import InlineMenu from './inline-menu' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/preact-text-color/src/components/editor/examples/text-color/extension.ts b/preact-text-color/src/components/editor/examples/text-color/extension.ts new file mode 100644 index 0000000000..d35d9d5c22 --- /dev/null +++ b/preact-text-color/src/components/editor/examples/text-color/extension.ts @@ -0,0 +1,14 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineBackgroundColor } from 'prosekit/extensions/background-color' +import { defineTextColor } from 'prosekit/extensions/text-color' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextColor(), + defineBackgroundColor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-text-color/src/components/editor/examples/text-color/index.ts b/preact-text-color/src/components/editor/examples/text-color/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-text-color/src/components/editor/examples/text-color/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-text-color/src/components/editor/examples/text-color/inline-menu.tsx b/preact-text-color/src/components/editor/examples/text-color/inline-menu.tsx new file mode 100644 index 0000000000..b1738229d5 --- /dev/null +++ b/preact-text-color/src/components/editor/examples/text-color/inline-menu.tsx @@ -0,0 +1,145 @@ +import { useMemo, useState } from 'preact/hooks' +import type { Editor, Keymap } from 'prosekit/core' +import { useEditorDerivedValue, useKeymap } from 'prosekit/preact' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/preact/inline-popover' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +const textColors = [ + { label: 'Gray', value: '#9ca3af' }, + { label: 'Brown', value: '#92400e' }, + { label: 'Orange', value: '#ea580c' }, + { label: 'Yellow', value: '#ca8a04' }, + { label: 'Green', value: '#16a34a' }, + { label: 'Blue', value: '#2563eb' }, + { label: 'Purple', value: '#9333ea' }, + { label: 'Magenta', value: '#c026d3' }, + { label: 'Red', value: '#dc2626' }, +] + +const backgroundColors = [ + { label: 'Gray', value: '#f3f4f6' }, + { label: 'Brown', value: '#fef3c7' }, + { label: 'Orange', value: '#ffedd5' }, + { label: 'Yellow', value: '#fef9c3' }, + { label: 'Green', value: '#d1fae5' }, + { label: 'Blue', value: '#dbeafe' }, + { label: 'Purple', value: '#e9d5ff' }, + { label: 'Pink', value: '#fce7f3' }, + { label: 'Red', value: '#fecaca' }, +] + +function getTextColorState(editor: Editor) { + return [ + { + label: 'Default', + value: 'currentColor', + isActive: !editor.marks.textColor.isActive(), + onClick: () => editor.commands.removeTextColor(), + }, + ].concat( + textColors.map((color) => ({ + label: color.label, + value: color.value, + isActive: editor.marks.textColor.isActive({ color: color.value }), + onClick: () => editor.commands.addTextColor({ color: color.value }), + })), + ) +} + +function getBackgroundColorState(editor: Editor) { + return [ + { + label: 'Default', + value: 'canvas', + isActive: !editor.marks.backgroundColor.isActive(), + onClick: () => editor.commands.removeBackgroundColor(), + }, + ].concat( + backgroundColors.map((color) => ({ + label: color.label, + value: color.value, + isActive: editor.marks.backgroundColor.isActive({ color: color.value }), + onClick: () => editor.commands.addBackgroundColor({ color: color.value }), + })), + ) +} + +export default function InlineMenu() { + const textColorState = useEditorDerivedValue(getTextColorState) + const backgroundColorState = useEditorDerivedValue(getBackgroundColorState) + const [open, setOpen] = useState(false) + + const keymap: Keymap = useMemo( + () => ({ + Escape: () => { + if (open) { + setOpen(false) + return true + } + return false + }, + }), + [open], + ) + + useKeymap(keymap) + + return ( + setOpen(event.detail)} + > + + +
+
+
Text color
+
+ {textColorState.map((color) => ( + + ))} +
+
+
+
Background color
+
+ {backgroundColorState.map((color) => ( + + ))} +
+
+
+
+
+
+ ) +} diff --git a/preact-text-color/src/components/editor/sample/sample-doc-text-color.ts b/preact-text-color/src/components/editor/sample/sample-doc-text-color.ts new file mode 100644 index 0000000000..a4efe4308d --- /dev/null +++ b/preact-text-color/src/components/editor/sample/sample-doc-text-color.ts @@ -0,0 +1,120 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#ef4444', + }, + }, + ], + text: 'Select', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#f97316', + }, + }, + ], + text: 'some', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#eab308', + }, + }, + ], + text: 'text', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#22c55e', + }, + }, + ], + text: 'to', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#3b82f6', + }, + }, + ], + text: 'change', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#6366f1', + }, + }, + ], + text: 'the', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#a855f7', + }, + }, + ], + text: 'color', + }, + ], + }, + ], +} diff --git a/preact-text-color/src/components/editor/ui/button/button.tsx b/preact-text-color/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-text-color/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-text-color/src/components/editor/ui/button/index.ts b/preact-text-color/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-text-color/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-text-color/src/main.tsx b/preact-text-color/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-text-color/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-text-color/tsconfig.app.json b/preact-text-color/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-text-color/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-text-color/tsconfig.json b/preact-text-color/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-text-color/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-text-color/tsconfig.node.json b/preact-text-color/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-text-color/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-text-color/vite.config.ts b/preact-text-color/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-text-color/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-toolbar/.gitignore b/preact-toolbar/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-toolbar/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-toolbar/README.md b/preact-toolbar/README.md new file mode 100644 index 0000000000..af46289faa --- /dev/null +++ b/preact-toolbar/README.md @@ -0,0 +1,15 @@ +# preact-toolbar + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-toolbar) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-toolbar) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-toolbar preact-toolbar +cd preact-toolbar +npm install +npm run dev +``` diff --git a/preact-toolbar/index.html b/preact-toolbar/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-toolbar/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-toolbar/package.json b/preact-toolbar/package.json new file mode 100644 index 0000000000..61d033d869 --- /dev/null +++ b/preact-toolbar/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-toolbar", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-toolbar/src/App.tsx b/preact-toolbar/src/App.tsx new file mode 100644 index 0000000000..72699e4f11 --- /dev/null +++ b/preact-toolbar/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/toolbar' + +export default function App() { + return +} diff --git a/preact-toolbar/src/app.css b/preact-toolbar/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-toolbar/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-toolbar/src/components/editor/examples/toolbar/editor.tsx b/preact-toolbar/src/components/editor/examples/toolbar/editor.tsx new file mode 100644 index 0000000000..8b0ef24501 --- /dev/null +++ b/preact-toolbar/src/components/editor/examples/toolbar/editor.tsx @@ -0,0 +1,32 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleUploader } from '../../sample/sample-uploader' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-toolbar/src/components/editor/examples/toolbar/extension.ts b/preact-toolbar/src/components/editor/examples/toolbar/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/preact-toolbar/src/components/editor/examples/toolbar/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/preact-toolbar/src/components/editor/examples/toolbar/index.ts b/preact-toolbar/src/components/editor/examples/toolbar/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-toolbar/src/components/editor/examples/toolbar/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-toolbar/src/components/editor/sample/sample-uploader.ts b/preact-toolbar/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/preact-toolbar/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/preact-toolbar/src/components/editor/ui/button/button.tsx b/preact-toolbar/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-toolbar/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-toolbar/src/components/editor/ui/button/index.ts b/preact-toolbar/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-toolbar/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/preact-toolbar/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-toolbar/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-toolbar/src/components/editor/ui/toolbar/index.ts b/preact-toolbar/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-toolbar/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-toolbar/src/components/editor/ui/toolbar/toolbar.tsx b/preact-toolbar/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-toolbar/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-toolbar/src/main.tsx b/preact-toolbar/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-toolbar/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-toolbar/tsconfig.app.json b/preact-toolbar/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-toolbar/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-toolbar/tsconfig.json b/preact-toolbar/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-toolbar/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-toolbar/tsconfig.node.json b/preact-toolbar/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-toolbar/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-toolbar/vite.config.ts b/preact-toolbar/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-toolbar/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-typography/.gitignore b/preact-typography/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-typography/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-typography/README.md b/preact-typography/README.md new file mode 100644 index 0000000000..f445617b64 --- /dev/null +++ b/preact-typography/README.md @@ -0,0 +1,15 @@ +# preact-typography + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-typography) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-typography) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-typography preact-typography +cd preact-typography +npm install +npm run dev +``` diff --git a/preact-typography/index.html b/preact-typography/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-typography/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-typography/package.json b/preact-typography/package.json new file mode 100644 index 0000000000..fdeab3839c --- /dev/null +++ b/preact-typography/package.json @@ -0,0 +1,26 @@ +{ + "name": "example-preact-typography", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-typography/src/App.tsx b/preact-typography/src/App.tsx new file mode 100644 index 0000000000..e1a59aa483 --- /dev/null +++ b/preact-typography/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/typography' + +export default function App() { + return +} diff --git a/preact-typography/src/app.css b/preact-typography/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-typography/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-typography/src/components/editor/examples/typography/editor.tsx b/preact-typography/src/components/editor/examples/typography/editor.tsx new file mode 100644 index 0000000000..e078a454d9 --- /dev/null +++ b/preact-typography/src/components/editor/examples/typography/editor.tsx @@ -0,0 +1,39 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-typography' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/preact-typography/src/components/editor/examples/typography/extension.ts b/preact-typography/src/components/editor/examples/typography/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/preact-typography/src/components/editor/examples/typography/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-typography/src/components/editor/examples/typography/index.ts b/preact-typography/src/components/editor/examples/typography/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-typography/src/components/editor/examples/typography/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-typography/src/components/editor/sample/katex.ts b/preact-typography/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/preact-typography/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/preact-typography/src/components/editor/sample/sample-doc-typography.ts b/preact-typography/src/components/editor/sample/sample-doc-typography.ts new file mode 100644 index 0000000000..db18b8155c --- /dev/null +++ b/preact-typography/src/components/editor/sample/sample-doc-typography.ts @@ -0,0 +1,693 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'ProseKit Typography', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This example shows the typography styles provided by ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'prosekit/basic/typography.css', + }, + { + type: 'text', + text: '.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Inline marks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Text can be formatted in different ways: ', + }, + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'bold text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'italic text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'underlined text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'strikethrough text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'inline code', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://example.com', + target: null, + rel: null, + }, + }, + ], + text: 'links', + }, + { + type: 'text', + text: ',', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'and hard breaks (Shift+Enter).', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Headings', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Heading 1', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Heading 2', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Heading 3', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 4, + }, + content: [ + { + type: 'text', + text: 'Heading 4', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 5, + }, + content: [ + { + type: 'text', + text: 'Heading 5', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 6, + }, + content: [ + { + type: 'text', + text: 'Heading 6', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Lists', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here are different types of lists:', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 1', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 2', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item A', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item B', + }, + ], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'First ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Second ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: true, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Completed task', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Pending task', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Blockquotes', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: '', + }, + content: [ + { + type: 'text', + text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Horizontal Rule', + }, + ], + }, + { + type: 'horizontalRule', + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blurred/640x360/42', + }, + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Tables', + }, + ], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 1', + }, + ], + }, + ], + }, + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 3', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 4', + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Math', + }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Inline math like Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text.' }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Block-level equations are displayed on their own line:', + }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + ], +} diff --git a/preact-typography/src/components/editor/ui/block-handle/block-handle.tsx b/preact-typography/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..8f5fe62e40 --- /dev/null +++ b/preact-typography/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,31 @@ +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/preact/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/preact-typography/src/components/editor/ui/block-handle/index.ts b/preact-typography/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/preact-typography/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/preact-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/preact-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx new file mode 100644 index 0000000000..6ace546a12 --- /dev/null +++ b/preact-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx @@ -0,0 +1,5 @@ +import { DropIndicator as BaseDropIndicator } from 'prosekit/preact/drop-indicator' + +export default function DropIndicator() { + return +} diff --git a/preact-typography/src/components/editor/ui/drop-indicator/index.ts b/preact-typography/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..f8fb7139c4 --- /dev/null +++ b/preact-typography/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator' diff --git a/preact-typography/src/main.tsx b/preact-typography/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-typography/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-typography/tsconfig.app.json b/preact-typography/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-typography/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-typography/tsconfig.json b/preact-typography/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-typography/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-typography/tsconfig.node.json b/preact-typography/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-typography/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-typography/vite.config.ts b/preact-typography/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-typography/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-underline/.gitignore b/preact-underline/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-underline/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-underline/README.md b/preact-underline/README.md new file mode 100644 index 0000000000..f27af34743 --- /dev/null +++ b/preact-underline/README.md @@ -0,0 +1,15 @@ +# preact-underline + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-underline) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-underline) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-underline preact-underline +cd preact-underline +npm install +npm run dev +``` diff --git a/preact-underline/index.html b/preact-underline/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-underline/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-underline/package.json b/preact-underline/package.json new file mode 100644 index 0000000000..e066a199d6 --- /dev/null +++ b/preact-underline/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-underline", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-underline/src/App.tsx b/preact-underline/src/App.tsx new file mode 100644 index 0000000000..6a03ee7870 --- /dev/null +++ b/preact-underline/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/underline' + +export default function App() { + return +} diff --git a/preact-underline/src/app.css b/preact-underline/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-underline/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-underline/src/components/editor/examples/underline/editor.tsx b/preact-underline/src/components/editor/examples/underline/editor.tsx new file mode 100644 index 0000000000..0125530635 --- /dev/null +++ b/preact-underline/src/components/editor/examples/underline/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-underline' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-underline/src/components/editor/examples/underline/extension.ts b/preact-underline/src/components/editor/examples/underline/extension.ts new file mode 100644 index 0000000000..16a9b58284 --- /dev/null +++ b/preact-underline/src/components/editor/examples/underline/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineUnderline(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-underline/src/components/editor/examples/underline/index.ts b/preact-underline/src/components/editor/examples/underline/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-underline/src/components/editor/examples/underline/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-underline/src/components/editor/sample/sample-doc-underline.ts b/preact-underline/src/components/editor/sample/sample-doc-underline.ts new file mode 100644 index 0000000000..6af561064b --- /dev/null +++ b/preact-underline/src/components/editor/sample/sample-doc-underline.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'This is underline', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/preact-underline/src/components/editor/ui/button/button.tsx b/preact-underline/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-underline/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-underline/src/components/editor/ui/button/index.ts b/preact-underline/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-underline/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-underline/src/components/editor/ui/image-upload-popover/index.ts b/preact-underline/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-underline/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-underline/src/components/editor/ui/toolbar/index.ts b/preact-underline/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-underline/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-underline/src/components/editor/ui/toolbar/toolbar.tsx b/preact-underline/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-underline/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-underline/src/main.tsx b/preact-underline/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-underline/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-underline/tsconfig.app.json b/preact-underline/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-underline/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-underline/tsconfig.json b/preact-underline/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-underline/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-underline/tsconfig.node.json b/preact-underline/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-underline/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-underline/vite.config.ts b/preact-underline/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-underline/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-unmount/.gitignore b/preact-unmount/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-unmount/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-unmount/README.md b/preact-unmount/README.md new file mode 100644 index 0000000000..414d115d56 --- /dev/null +++ b/preact-unmount/README.md @@ -0,0 +1,15 @@ +# preact-unmount + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-unmount) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-unmount) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-unmount preact-unmount +cd preact-unmount +npm install +npm run dev +``` diff --git a/preact-unmount/index.html b/preact-unmount/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-unmount/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-unmount/package.json b/preact-unmount/package.json new file mode 100644 index 0000000000..09feac1f1b --- /dev/null +++ b/preact-unmount/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-unmount", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-unmount/src/App.tsx b/preact-unmount/src/App.tsx new file mode 100644 index 0000000000..da35bea56f --- /dev/null +++ b/preact-unmount/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/unmount' + +export default function App() { + return +} diff --git a/preact-unmount/src/app.css b/preact-unmount/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-unmount/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-unmount/src/components/editor/examples/unmount/editor-component.tsx b/preact-unmount/src/components/editor/examples/unmount/editor-component.tsx new file mode 100644 index 0000000000..975a584f21 --- /dev/null +++ b/preact-unmount/src/components/editor/examples/unmount/editor-component.tsx @@ -0,0 +1,32 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { InlineMenu } from '../../ui/inline-menu' + +import ExtensionComponent from './extension-component' + +export default function EditorComponent(props: { placeholder: string }) { + const editor = useMemo(() => { + return createEditor({ extension: defineBasicExtension() }) + }, []) + + return ( + +
+
+
+ +
+
+ +
+ ) +} diff --git a/preact-unmount/src/components/editor/examples/unmount/editor.tsx b/preact-unmount/src/components/editor/examples/unmount/editor.tsx new file mode 100644 index 0000000000..d54f0a7591 --- /dev/null +++ b/preact-unmount/src/components/editor/examples/unmount/editor.tsx @@ -0,0 +1,44 @@ +import { useCallback, useRef, useState } from 'preact/hooks' + +import EditorComponent from './editor-component' + +function EditorGroup() { + const nextKeyRef = useRef(1) + const [editorKeys, setEditorKeys] = useState([]) + + const addEditor = useCallback(() => { + const key = nextKeyRef.current + nextKeyRef.current += 1 + setEditorKeys((keys) => [...keys, key]) + }, []) + + const removeEditor = useCallback((key: number) => { + setEditorKeys((keys) => keys.filter((k) => k !== key)) + }, []) + + return ( +
+
+ + {editorKeys.map((key) => ( + + ))} +
+ {editorKeys.map((key) => ( +
+ +
+ ))} +
+ ) +} + +export default EditorGroup diff --git a/preact-unmount/src/components/editor/examples/unmount/extension-component.tsx b/preact-unmount/src/components/editor/examples/unmount/extension-component.tsx new file mode 100644 index 0000000000..d5c811532f --- /dev/null +++ b/preact-unmount/src/components/editor/examples/unmount/extension-component.tsx @@ -0,0 +1,14 @@ +import { useMemo } from 'preact/hooks' +import { definePlaceholder } from 'prosekit/extensions/placeholder' +import { useExtension } from 'prosekit/preact' + +export default function ExtensionComponent(props: { placeholder: string }) { + const extension = useMemo( + () => definePlaceholder({ placeholder: props.placeholder }), + [props.placeholder], + ) + + useExtension(extension) + + return null +} diff --git a/preact-unmount/src/components/editor/examples/unmount/index.ts b/preact-unmount/src/components/editor/examples/unmount/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-unmount/src/components/editor/examples/unmount/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-unmount/src/components/editor/ui/button/button.tsx b/preact-unmount/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-unmount/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-unmount/src/components/editor/ui/button/index.ts b/preact-unmount/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-unmount/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-unmount/src/components/editor/ui/inline-menu/index.ts b/preact-unmount/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/preact-unmount/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/preact-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx b/preact-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..a014b74f57 --- /dev/null +++ b/preact-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +import type { JSX } from 'preact' +import { useState } from 'preact/hooks' +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/preact' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/preact/inline-popover' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + const handleSubmit = ( + event: JSX.TargetedEvent, + ) => { + event.preventDefault() + const href = event.currentTarget.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
+ +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/preact-unmount/src/main.tsx b/preact-unmount/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-unmount/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-unmount/tsconfig.app.json b/preact-unmount/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-unmount/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-unmount/tsconfig.json b/preact-unmount/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-unmount/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-unmount/tsconfig.node.json b/preact-unmount/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-unmount/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-unmount/vite.config.ts b/preact-unmount/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-unmount/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-user-menu-dynamic/.gitignore b/preact-user-menu-dynamic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-user-menu-dynamic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-user-menu-dynamic/README.md b/preact-user-menu-dynamic/README.md new file mode 100644 index 0000000000..491cefb490 --- /dev/null +++ b/preact-user-menu-dynamic/README.md @@ -0,0 +1,15 @@ +# preact-user-menu-dynamic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-user-menu-dynamic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-user-menu-dynamic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-user-menu-dynamic preact-user-menu-dynamic +cd preact-user-menu-dynamic +npm install +npm run dev +``` diff --git a/preact-user-menu-dynamic/index.html b/preact-user-menu-dynamic/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-user-menu-dynamic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-user-menu-dynamic/package.json b/preact-user-menu-dynamic/package.json new file mode 100644 index 0000000000..b313be6d61 --- /dev/null +++ b/preact-user-menu-dynamic/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-user-menu-dynamic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-user-menu-dynamic/src/App.tsx b/preact-user-menu-dynamic/src/App.tsx new file mode 100644 index 0000000000..e3ec0e7b10 --- /dev/null +++ b/preact-user-menu-dynamic/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/user-menu-dynamic' + +export default function App() { + return +} diff --git a/preact-user-menu-dynamic/src/app.css b/preact-user-menu-dynamic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-user-menu-dynamic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx new file mode 100644 index 0000000000..17d6c2f85a --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx @@ -0,0 +1,30 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { defineExtension } from './extension' +import UserMenuDynamic from './user-menu-dynamic' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts new file mode 100644 index 0000000000..ff2c40b104 --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts new file mode 100644 index 0000000000..06176376bd --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts @@ -0,0 +1,40 @@ +import { useEffect, useState } from 'preact/hooks' + +import type { User } from '../../sample/sample-query-users' +import { queryUsers } from '../../sample/sample-query-users' + +/** + * Simulate a user searching with some delay. + */ +export function useUserQuery(query: string, enabled: boolean) { + const [users, setUsers] = useState([]) + const [loading, setLoading] = useState(true) + + if (!enabled && users.length > 0) { + setUsers([]) + } + + useEffect(() => { + if (!enabled) { + return + } + + let cancelled = false + + void (async () => { + setLoading(true) + const filteredUsers = await queryUsers(query) + if (cancelled) { + return + } + setUsers(filteredUsers) + setLoading(false) + })() + + return () => { + cancelled = true + } + }, [enabled, query]) + + return { loading, users } +} diff --git a/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx new file mode 100644 index 0000000000..18fc7611b1 --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx @@ -0,0 +1,21 @@ +import { useState } from 'preact/hooks' + +import { UserMenu } from '../../ui/user-menu' + +import { useUserQuery } from './use-user-query' + +export default function UserMenuDynamic() { + const [query, setQuery] = useState('') + const [open, setOpen] = useState(false) + + const { loading, users } = useUserQuery(query, open) + + return ( + + ) +} diff --git a/preact-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/preact-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts new file mode 100644 index 0000000000..ab78fd5525 --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts @@ -0,0 +1,40 @@ +import { users } from './sample-user-data' + +export interface User { + id: number + name: string +} + +const connectHandlers: VoidFunction[] = [] +let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' + +/** + * A utility function to simulate different network states. Useful for testing. + * + * @internal + */ +export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { + networkStatus = status + if (status !== 'offline') { + connectHandlers.forEach((handler) => handler()) + connectHandlers.length = 0 + } +} + +/** + * Simulate a user searching with some delay. + */ +export async function queryUsers(query: string): Promise { + if (networkStatus === 'offline') { + await new Promise((resolve) => connectHandlers.push(resolve)) + } + if (networkStatus === 'slow') { + await new Promise((resolve) => setTimeout(resolve, 300)) + } + + const normalizedQuery = query.toLowerCase().trim() + const filteredUsers = users + .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) + .slice(0, 10) + return filteredUsers +} diff --git a/preact-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/preact-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/preact-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/preact-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/preact-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx b/preact-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..39b78adbde --- /dev/null +++ b/preact-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,62 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/preact' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/preact/autocomplete' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}) { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + {props.users.map((user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + ))} +
+
+
+
+ ) +} diff --git a/preact-user-menu-dynamic/src/main.tsx b/preact-user-menu-dynamic/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-user-menu-dynamic/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-user-menu-dynamic/tsconfig.app.json b/preact-user-menu-dynamic/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-user-menu-dynamic/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-user-menu-dynamic/tsconfig.json b/preact-user-menu-dynamic/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-user-menu-dynamic/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-user-menu-dynamic/tsconfig.node.json b/preact-user-menu-dynamic/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-user-menu-dynamic/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-user-menu-dynamic/vite.config.ts b/preact-user-menu-dynamic/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-user-menu-dynamic/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-user-menu/.gitignore b/preact-user-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-user-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-user-menu/README.md b/preact-user-menu/README.md new file mode 100644 index 0000000000..0d439b55a2 --- /dev/null +++ b/preact-user-menu/README.md @@ -0,0 +1,15 @@ +# preact-user-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-user-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-user-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-user-menu preact-user-menu +cd preact-user-menu +npm install +npm run dev +``` diff --git a/preact-user-menu/index.html b/preact-user-menu/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-user-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-user-menu/package.json b/preact-user-menu/package.json new file mode 100644 index 0000000000..69b58f970e --- /dev/null +++ b/preact-user-menu/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-user-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-user-menu/src/App.tsx b/preact-user-menu/src/App.tsx new file mode 100644 index 0000000000..92fca03d42 --- /dev/null +++ b/preact-user-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/user-menu' + +export default function App() { + return +} diff --git a/preact-user-menu/src/app.css b/preact-user-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-user-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-user-menu/src/components/editor/examples/user-menu/editor.tsx b/preact-user-menu/src/components/editor/examples/user-menu/editor.tsx new file mode 100644 index 0000000000..2cdd458403 --- /dev/null +++ b/preact-user-menu/src/components/editor/examples/user-menu/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { tags } from '../../sample/sample-tag-data' +import { users } from '../../sample/sample-user-data' +import { TagMenu } from '../../ui/tag-menu' +import { UserMenu } from '../../ui/user-menu' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/preact-user-menu/src/components/editor/examples/user-menu/extension.ts b/preact-user-menu/src/components/editor/examples/user-menu/extension.ts new file mode 100644 index 0000000000..56a97a4779 --- /dev/null +++ b/preact-user-menu/src/components/editor/examples/user-menu/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone or # to tag something...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/preact-user-menu/src/components/editor/examples/user-menu/index.ts b/preact-user-menu/src/components/editor/examples/user-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-user-menu/src/components/editor/examples/user-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-user-menu/src/components/editor/sample/sample-tag-data.ts b/preact-user-menu/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/preact-user-menu/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/preact-user-menu/src/components/editor/sample/sample-user-data.ts b/preact-user-menu/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/preact-user-menu/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/preact-user-menu/src/components/editor/ui/tag-menu/index.ts b/preact-user-menu/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..d344b33a70 --- /dev/null +++ b/preact-user-menu/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu' diff --git a/preact-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx b/preact-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx new file mode 100644 index 0000000000..00b3e4b085 --- /dev/null +++ b/preact-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx @@ -0,0 +1,52 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/preact' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/preact/autocomplete' + +const regex = /#[\da-z]*$/i + +export default function TagMenu(props: { + tags: { id: number; label: string }[] +}) { + const editor = useEditor>() + + const handleTagInsert = (id: number, label: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '#' + label, + kind: 'tag', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + + + +
+ + No results + + + {props.tags.map((tag) => ( + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + ))} +
+
+
+
+ ) +} diff --git a/preact-user-menu/src/components/editor/ui/user-menu/index.ts b/preact-user-menu/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/preact-user-menu/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/preact-user-menu/src/components/editor/ui/user-menu/user-menu.tsx b/preact-user-menu/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..39b78adbde --- /dev/null +++ b/preact-user-menu/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,62 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/preact' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/preact/autocomplete' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}) { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + {props.users.map((user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + ))} +
+
+
+
+ ) +} diff --git a/preact-user-menu/src/main.tsx b/preact-user-menu/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-user-menu/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-user-menu/tsconfig.app.json b/preact-user-menu/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-user-menu/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-user-menu/tsconfig.json b/preact-user-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-user-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-user-menu/tsconfig.node.json b/preact-user-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-user-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-user-menu/vite.config.ts b/preact-user-menu/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-user-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-word-counter/.gitignore b/preact-word-counter/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-word-counter/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-word-counter/README.md b/preact-word-counter/README.md new file mode 100644 index 0000000000..1f6eb025dc --- /dev/null +++ b/preact-word-counter/README.md @@ -0,0 +1,15 @@ +# preact-word-counter + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-word-counter) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-word-counter) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-word-counter preact-word-counter +cd preact-word-counter +npm install +npm run dev +``` diff --git a/preact-word-counter/index.html b/preact-word-counter/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-word-counter/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-word-counter/package.json b/preact-word-counter/package.json new file mode 100644 index 0000000000..8fde8484a0 --- /dev/null +++ b/preact-word-counter/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-preact-word-counter", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-word-counter/src/App.tsx b/preact-word-counter/src/App.tsx new file mode 100644 index 0000000000..9da98dddb5 --- /dev/null +++ b/preact-word-counter/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/word-counter' + +export default function App() { + return +} diff --git a/preact-word-counter/src/app.css b/preact-word-counter/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-word-counter/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-word-counter/src/components/editor/examples/word-counter/editor.tsx b/preact-word-counter/src/components/editor/examples/word-counter/editor.tsx new file mode 100644 index 0000000000..a4249ea763 --- /dev/null +++ b/preact-word-counter/src/components/editor/examples/word-counter/editor.tsx @@ -0,0 +1,40 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { useMemo } from 'preact/hooks' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' + +import { sampleContent } from '../../sample/sample-doc-word-counter' +import { WordCounter } from '../../ui/word-counter' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ + extension, + defaultContent, + }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/preact-word-counter/src/components/editor/examples/word-counter/extension.ts b/preact-word-counter/src/components/editor/examples/word-counter/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/preact-word-counter/src/components/editor/examples/word-counter/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/preact-word-counter/src/components/editor/examples/word-counter/index.ts b/preact-word-counter/src/components/editor/examples/word-counter/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-word-counter/src/components/editor/examples/word-counter/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/preact-word-counter/src/components/editor/sample/sample-doc-word-counter.ts new file mode 100644 index 0000000000..0b5d435038 --- /dev/null +++ b/preact-word-counter/src/components/editor/sample/sample-doc-word-counter.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Start typing and observe the word count update below.', + }, + ], + }, + ], +} diff --git a/preact-word-counter/src/components/editor/ui/word-counter/index.ts b/preact-word-counter/src/components/editor/ui/word-counter/index.ts new file mode 100644 index 0000000000..929ee3e41a --- /dev/null +++ b/preact-word-counter/src/components/editor/ui/word-counter/index.ts @@ -0,0 +1 @@ +export { default as WordCounter } from './word-counter' diff --git a/preact-word-counter/src/components/editor/ui/word-counter/word-counter.tsx b/preact-word-counter/src/components/editor/ui/word-counter/word-counter.tsx new file mode 100644 index 0000000000..53d8f88097 --- /dev/null +++ b/preact-word-counter/src/components/editor/ui/word-counter/word-counter.tsx @@ -0,0 +1,22 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/preact' + +function getWordCount(editor: Editor) { + const doc = editor.state.doc + const words = doc ? doc.textBetween(0, doc.content.size, ' ') : '' + const wordCount = words.split(/\s+/).filter((s) => s).length + const characterCount = doc ? doc.textContent.length : 0 + return { wordCount, characterCount } +} + +export default function WordCounter() { + const { wordCount, characterCount } = useEditorDerivedValue(getWordCount) + + return ( +
+ Word Count: {wordCount} +
+ Character Count: {characterCount} +
+ ) +} diff --git a/preact-word-counter/src/main.tsx b/preact-word-counter/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-word-counter/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-word-counter/tsconfig.app.json b/preact-word-counter/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-word-counter/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-word-counter/tsconfig.json b/preact-word-counter/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-word-counter/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-word-counter/tsconfig.node.json b/preact-word-counter/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-word-counter/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-word-counter/vite.config.ts b/preact-word-counter/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-word-counter/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/preact-yjs/.gitignore b/preact-yjs/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/preact-yjs/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/preact-yjs/README.md b/preact-yjs/README.md new file mode 100644 index 0000000000..f973bc3abc --- /dev/null +++ b/preact-yjs/README.md @@ -0,0 +1,15 @@ +# preact-yjs + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/preact-yjs) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/preact-yjs) + +Run the example locally with: + +```bash +npx degit prosekit/examples/preact-yjs preact-yjs +cd preact-yjs +npm install +npm run dev +``` diff --git a/preact-yjs/index.html b/preact-yjs/index.html new file mode 100644 index 0000000000..b4f79f2233 --- /dev/null +++ b/preact-yjs/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Preact + + +
+ + + diff --git a/preact-yjs/package.json b/preact-yjs/package.json new file mode 100644 index 0000000000..7333ba02b5 --- /dev/null +++ b/preact-yjs/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-preact-yjs", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "preact": "^10.29.1", + "prosekit": "^0.21.0", + "y-prosemirror": "^1.3.7", + "y-websocket": "^3.0.0", + "yjs": "^13.6.30" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@preact/preset-vite": "^2.10.5", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/preact-yjs/src/App.tsx b/preact-yjs/src/App.tsx new file mode 100644 index 0000000000..8641aefe47 --- /dev/null +++ b/preact-yjs/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/yjs' + +export default function App() { + return +} diff --git a/preact-yjs/src/app.css b/preact-yjs/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/preact-yjs/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/preact-yjs/src/components/editor/examples/yjs/editor-component.tsx b/preact-yjs/src/components/editor/examples/yjs/editor-component.tsx new file mode 100644 index 0000000000..e5385a4ca3 --- /dev/null +++ b/preact-yjs/src/components/editor/examples/yjs/editor-component.tsx @@ -0,0 +1,41 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/yjs/style.css' + +import { useMemo } from 'preact/hooks' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/preact' +import { WebsocketProvider } from 'y-websocket' +import * as Y from 'yjs' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function EditorComponent(props: { room?: string }) { + const editor = useMemo(() => { + const doc = new Y.Doc() + const provider = new WebsocketProvider( + 'wss://demos.yjs.dev/ws', + `github.com/prosekit/room_${props.room}`, + doc, + ) + + const extension = defineExtension(doc, provider.awareness) + return createEditor({ extension }) + }, [props.room]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/preact-yjs/src/components/editor/examples/yjs/editor.tsx b/preact-yjs/src/components/editor/examples/yjs/editor.tsx new file mode 100644 index 0000000000..be276b5b1d --- /dev/null +++ b/preact-yjs/src/components/editor/examples/yjs/editor.tsx @@ -0,0 +1,16 @@ +import { useState } from 'preact/hooks' + +import EditorComponent from './editor-component' + +export default function Page() { + const [room] = useState(() => { + return Math.random().toString(36).substring(2, 15) + }) + + return ( +
+ + +
+ ) +} diff --git a/preact-yjs/src/components/editor/examples/yjs/extension.ts b/preact-yjs/src/components/editor/examples/yjs/extension.ts new file mode 100644 index 0000000000..f1a581932b --- /dev/null +++ b/preact-yjs/src/components/editor/examples/yjs/extension.ts @@ -0,0 +1,48 @@ +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' +import { defineYjs } from 'prosekit/extensions/yjs' +import type { Awareness } from 'prosekit/extensions/yjs' +import type * as Y from 'yjs' + +export function defineExtension(doc: Y.Doc, awareness: Awareness) { + return union([ + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineYjs({ doc, awareness }), + ]) +} + +export type EditorExtension = ReturnType diff --git a/preact-yjs/src/components/editor/examples/yjs/index.ts b/preact-yjs/src/components/editor/examples/yjs/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/preact-yjs/src/components/editor/examples/yjs/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/preact-yjs/src/components/editor/ui/button/button.tsx b/preact-yjs/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..8df85bcb7d --- /dev/null +++ b/preact-yjs/src/components/editor/ui/button/button.tsx @@ -0,0 +1,44 @@ +import type { ComponentChild, MouseEventHandler } from 'preact' +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/preact/tooltip' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ComponentChild +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/preact-yjs/src/components/editor/ui/button/index.ts b/preact-yjs/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/preact-yjs/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/preact-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/preact-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..764667a8c0 --- /dev/null +++ b/preact-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,144 @@ +import type { ComponentChild, JSX } from 'preact' +import { useId, useState } from 'preact/hooks' +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/preact' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/preact/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ComponentChild +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange = ( + event: JSX.TargetedEvent, + ) => { + const file = event.currentTarget.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = ( + event: JSX.TargetedEvent, + ) => { + const url = event.currentTarget.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/preact-yjs/src/components/editor/ui/image-upload-popover/index.ts b/preact-yjs/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/preact-yjs/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/preact-yjs/src/components/editor/ui/toolbar/index.ts b/preact-yjs/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/preact-yjs/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/preact-yjs/src/components/editor/ui/toolbar/toolbar.tsx b/preact-yjs/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..746a58435a --- /dev/null +++ b/preact-yjs/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,363 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/preact' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/preact-yjs/src/main.tsx b/preact-yjs/src/main.tsx new file mode 100644 index 0000000000..9452b5673a --- /dev/null +++ b/preact-yjs/src/main.tsx @@ -0,0 +1,5 @@ +import './app.css' +import { render } from 'preact' +import App from './App.tsx' + +render(, document.getElementById('app')!) diff --git a/preact-yjs/tsconfig.app.json b/preact-yjs/tsconfig.app.json new file mode 100644 index 0000000000..3fe3ab979d --- /dev/null +++ b/preact-yjs/tsconfig.app.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + "paths": { + "react": ["./node_modules/preact/compat/"], + "react-dom": ["./node_modules/preact/compat/"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "jsxImportSource": "preact", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/preact-yjs/tsconfig.json b/preact-yjs/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/preact-yjs/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/preact-yjs/tsconfig.node.json b/preact-yjs/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/preact-yjs/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/preact-yjs/vite.config.ts b/preact-yjs/vite.config.ts new file mode 100644 index 0000000000..5e0b3c9e1a --- /dev/null +++ b/preact-yjs/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import preact from '@preact/preset-vite' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [preact(), tailwindcss()], +}) diff --git a/react-block-handle/.gitignore b/react-block-handle/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-block-handle/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-block-handle/README.md b/react-block-handle/README.md new file mode 100644 index 0000000000..4d954899ce --- /dev/null +++ b/react-block-handle/README.md @@ -0,0 +1,15 @@ +# react-block-handle + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-block-handle) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-block-handle) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-block-handle react-block-handle +cd react-block-handle +npm install +npm run dev +``` diff --git a/react-block-handle/index.html b/react-block-handle/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-block-handle/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-block-handle/package.json b/react-block-handle/package.json new file mode 100644 index 0000000000..bd38922d46 --- /dev/null +++ b/react-block-handle/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-block-handle", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-block-handle/src/App.tsx b/react-block-handle/src/App.tsx new file mode 100644 index 0000000000..2cb5b6bb8d --- /dev/null +++ b/react-block-handle/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/block-handle' + +export default function App() { + return +} diff --git a/react-block-handle/src/app.css b/react-block-handle/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-block-handle/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-block-handle/src/components/editor/examples/block-handle/editor.tsx b/react-block-handle/src/components/editor/examples/block-handle/editor.tsx new file mode 100644 index 0000000000..b6512f948e --- /dev/null +++ b/react-block-handle/src/components/editor/examples/block-handle/editor.tsx @@ -0,0 +1,41 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-block-handle' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/react-block-handle/src/components/editor/examples/block-handle/extension.ts b/react-block-handle/src/components/editor/examples/block-handle/extension.ts new file mode 100644 index 0000000000..2c6a5383ad --- /dev/null +++ b/react-block-handle/src/components/editor/examples/block-handle/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union([defineBasicExtension(), defineCodeBlockView()]) +} + +export type EditorExtension = ReturnType diff --git a/react-block-handle/src/components/editor/examples/block-handle/index.ts b/react-block-handle/src/components/editor/examples/block-handle/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-block-handle/src/components/editor/examples/block-handle/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/react-block-handle/src/components/editor/sample/sample-doc-block-handle.ts new file mode 100644 index 0000000000..3c6ccdc203 --- /dev/null +++ b/react-block-handle/src/components/editor/sample/sample-doc-block-handle.ts @@ -0,0 +1,323 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Drag and Drop Demo', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Getting Started', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This paragraph can be moved above or below other blocks.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Different Block Types', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'You can drag paragraphs, headings, lists, code blocks, and more.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Lists Work Too', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This entire list can be dragged', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Individual list items stay together', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try moving this list around', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Ordered lists also support dragging', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The numbering updates automatically', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag this list to see it in action', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Even code blocks can be moved:', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: 'javascript', + }, + content: [ + { + type: 'text', + text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Nested Content', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This blockquote can be moved as a single unit.', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested blockquotes move together with their parent.', + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Try It Yourself', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Practice by moving this paragraph to the top of the document.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Or drag this one to between the headings above.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The drag handles make it easy to reorganize your content exactly how you want it.', + }, + ], + }, + ], +} diff --git a/react-block-handle/src/components/editor/ui/block-handle/block-handle.tsx b/react-block-handle/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..3cc6028d5c --- /dev/null +++ b/react-block-handle/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,33 @@ +'use client' + +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/react/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/react-block-handle/src/components/editor/ui/block-handle/index.ts b/react-block-handle/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/react-block-handle/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/react-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx b/react-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..f6c0428091 --- /dev/null +++ b/react-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,39 @@ +'use client' + +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { ReactNodeViewProps } from 'prosekit/react' + +export default function CodeBlockView(props: ReactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/react-block-handle/src/components/editor/ui/code-block-view/index.ts b/react-block-handle/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..b7e6b996bc
--- /dev/null
+++ b/react-block-handle/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineReactNodeView,
+  type ReactNodeViewComponent,
+} from 'prosekit/react'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineReactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies ReactNodeViewComponent,
+  })
+}
diff --git a/react-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/react-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
new file mode 100644
index 0000000000..87c1746622
--- /dev/null
+++ b/react-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
@@ -0,0 +1,7 @@
+'use client'
+
+import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator'
+
+export default function DropIndicator() {
+  return 
+}
diff --git a/react-block-handle/src/components/editor/ui/drop-indicator/index.ts b/react-block-handle/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..f8fb7139c4
--- /dev/null
+++ b/react-block-handle/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator'
diff --git a/react-block-handle/src/main.tsx b/react-block-handle/src/main.tsx
new file mode 100644
index 0000000000..87de8eb52b
--- /dev/null
+++ b/react-block-handle/src/main.tsx
@@ -0,0 +1,10 @@
+import './app.css'
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App.tsx'
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+  
+    
+  ,
+)
diff --git a/react-block-handle/tsconfig.app.json b/react-block-handle/tsconfig.app.json
new file mode 100644
index 0000000000..a9b5a59ca6
--- /dev/null
+++ b/react-block-handle/tsconfig.app.json
@@ -0,0 +1,28 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "target": "ES2022",
+    "useDefineForClassFields": true,
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "module": "ESNext",
+    "types": ["vite/client"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+    "jsx": "react-jsx",
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["src"]
+}
diff --git a/react-block-handle/tsconfig.json b/react-block-handle/tsconfig.json
new file mode 100644
index 0000000000..1ffef600d9
--- /dev/null
+++ b/react-block-handle/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "files": [],
+  "references": [
+    { "path": "./tsconfig.app.json" },
+    { "path": "./tsconfig.node.json" }
+  ]
+}
diff --git a/react-block-handle/tsconfig.node.json b/react-block-handle/tsconfig.node.json
new file mode 100644
index 0000000000..8a67f62f4c
--- /dev/null
+++ b/react-block-handle/tsconfig.node.json
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "target": "ES2023",
+    "lib": ["ES2023"],
+    "module": "ESNext",
+    "types": ["node"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/react-block-handle/vite.config.ts b/react-block-handle/vite.config.ts
new file mode 100644
index 0000000000..c90997597d
--- /dev/null
+++ b/react-block-handle/vite.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import tailwindcss from '@tailwindcss/vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [react(), tailwindcss()],
+})
diff --git a/react-blockquote/.gitignore b/react-blockquote/.gitignore
new file mode 100644
index 0000000000..5d6225c6df
--- /dev/null
+++ b/react-blockquote/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+.next
+.svelte-kit
diff --git a/react-blockquote/README.md b/react-blockquote/README.md
new file mode 100644
index 0000000000..93713fd42d
--- /dev/null
+++ b/react-blockquote/README.md
@@ -0,0 +1,15 @@
+# react-blockquote
+
+A [ProseKit](https://prosekit.dev) example.
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-blockquote)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-blockquote)
+
+Run the example locally with:
+
+```bash
+npx degit prosekit/examples/react-blockquote react-blockquote
+cd react-blockquote
+npm install
+npm run dev
+```
diff --git a/react-blockquote/index.html b/react-blockquote/index.html
new file mode 100644
index 0000000000..a5a78f3bf8
--- /dev/null
+++ b/react-blockquote/index.html
@@ -0,0 +1,12 @@
+
+
+  
+    
+    
+    ProseKit + React
+  
+  
+    
+ + + diff --git a/react-blockquote/package.json b/react-blockquote/package.json new file mode 100644 index 0000000000..eb2c784b90 --- /dev/null +++ b/react-blockquote/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-blockquote", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-blockquote/src/App.tsx b/react-blockquote/src/App.tsx new file mode 100644 index 0000000000..3327cfcf2d --- /dev/null +++ b/react-blockquote/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/blockquote' + +export default function App() { + return +} diff --git a/react-blockquote/src/app.css b/react-blockquote/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-blockquote/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-blockquote/src/components/editor/examples/blockquote/editor.tsx b/react-blockquote/src/components/editor/examples/blockquote/editor.tsx new file mode 100644 index 0000000000..cbf25168cf --- /dev/null +++ b/react-blockquote/src/components/editor/examples/blockquote/editor.tsx @@ -0,0 +1,32 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + return createEditor({ extension: defineExtension() }) + }, []) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-blockquote/src/components/editor/examples/blockquote/extension.ts b/react-blockquote/src/components/editor/examples/blockquote/extension.ts new file mode 100644 index 0000000000..5292b59e35 --- /dev/null +++ b/react-blockquote/src/components/editor/examples/blockquote/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBlockquote(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-blockquote/src/components/editor/examples/blockquote/index.ts b/react-blockquote/src/components/editor/examples/blockquote/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-blockquote/src/components/editor/examples/blockquote/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-blockquote/src/components/editor/ui/button/button.tsx b/react-blockquote/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-blockquote/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-blockquote/src/components/editor/ui/button/index.ts b/react-blockquote/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-blockquote/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/react-blockquote/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-blockquote/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-blockquote/src/components/editor/ui/toolbar/index.ts b/react-blockquote/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-blockquote/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-blockquote/src/components/editor/ui/toolbar/toolbar.tsx b/react-blockquote/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-blockquote/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-blockquote/src/main.tsx b/react-blockquote/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-blockquote/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-blockquote/tsconfig.app.json b/react-blockquote/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-blockquote/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-blockquote/tsconfig.json b/react-blockquote/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-blockquote/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-blockquote/tsconfig.node.json b/react-blockquote/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-blockquote/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-blockquote/vite.config.ts b/react-blockquote/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-blockquote/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-bold/.gitignore b/react-bold/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-bold/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-bold/README.md b/react-bold/README.md new file mode 100644 index 0000000000..dec2aa3c99 --- /dev/null +++ b/react-bold/README.md @@ -0,0 +1,15 @@ +# react-bold + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-bold) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-bold) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-bold react-bold +cd react-bold +npm install +npm run dev +``` diff --git a/react-bold/index.html b/react-bold/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-bold/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-bold/package.json b/react-bold/package.json new file mode 100644 index 0000000000..0565ff79e7 --- /dev/null +++ b/react-bold/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-bold", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-bold/src/App.tsx b/react-bold/src/App.tsx new file mode 100644 index 0000000000..274955047d --- /dev/null +++ b/react-bold/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/bold' + +export default function App() { + return +} diff --git a/react-bold/src/app.css b/react-bold/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-bold/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-bold/src/components/editor/examples/bold/editor.tsx b/react-bold/src/components/editor/examples/bold/editor.tsx new file mode 100644 index 0000000000..4fed923fec --- /dev/null +++ b/react-bold/src/components/editor/examples/bold/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-bold' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-bold/src/components/editor/examples/bold/extension.ts b/react-bold/src/components/editor/examples/bold/extension.ts new file mode 100644 index 0000000000..eaa4fba721 --- /dev/null +++ b/react-bold/src/components/editor/examples/bold/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBold } from 'prosekit/extensions/bold' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBold(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-bold/src/components/editor/examples/bold/index.ts b/react-bold/src/components/editor/examples/bold/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-bold/src/components/editor/examples/bold/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-bold/src/components/editor/sample/sample-doc-bold.ts b/react-bold/src/components/editor/sample/sample-doc-bold.ts new file mode 100644 index 0000000000..09ed08daad --- /dev/null +++ b/react-bold/src/components/editor/sample/sample-doc-bold.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/react-bold/src/components/editor/ui/button/button.tsx b/react-bold/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-bold/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-bold/src/components/editor/ui/button/index.ts b/react-bold/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-bold/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-bold/src/components/editor/ui/image-upload-popover/index.ts b/react-bold/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-bold/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-bold/src/components/editor/ui/toolbar/index.ts b/react-bold/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-bold/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-bold/src/components/editor/ui/toolbar/toolbar.tsx b/react-bold/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-bold/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-bold/src/main.tsx b/react-bold/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-bold/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-bold/tsconfig.app.json b/react-bold/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-bold/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-bold/tsconfig.json b/react-bold/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-bold/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-bold/tsconfig.node.json b/react-bold/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-bold/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-bold/vite.config.ts b/react-bold/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-bold/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-change-tracking/.gitignore b/react-change-tracking/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-change-tracking/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-change-tracking/README.md b/react-change-tracking/README.md new file mode 100644 index 0000000000..adb28d3ffc --- /dev/null +++ b/react-change-tracking/README.md @@ -0,0 +1,15 @@ +# react-change-tracking + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-change-tracking) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-change-tracking) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-change-tracking react-change-tracking +cd react-change-tracking +npm install +npm run dev +``` diff --git a/react-change-tracking/index.html b/react-change-tracking/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-change-tracking/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-change-tracking/package.json b/react-change-tracking/package.json new file mode 100644 index 0000000000..16a65a985d --- /dev/null +++ b/react-change-tracking/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-change-tracking", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-change-tracking/src/App.tsx b/react-change-tracking/src/App.tsx new file mode 100644 index 0000000000..88160e69c9 --- /dev/null +++ b/react-change-tracking/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/change-tracking' + +export default function App() { + return +} diff --git a/react-change-tracking/src/app.css b/react-change-tracking/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-change-tracking/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx b/react-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx new file mode 100644 index 0000000000..80f3378002 --- /dev/null +++ b/react-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx @@ -0,0 +1,32 @@ +'use client' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, union } from 'prosekit/core' +import { defineCommitViewer, type Commit } from 'prosekit/extensions/commit' +import { defineReadonly } from 'prosekit/extensions/readonly' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +export default function EditorDiff(props: { commit: Commit }) { + const editor = useMemo(() => { + const extension = union( + defineBasicExtension(), + defineReadonly(), + defineCommitViewer(props.commit), + ) + return createEditor({ extension }) + }, [props.commit]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx b/react-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx new file mode 100644 index 0000000000..61ff6200cf --- /dev/null +++ b/react-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, union, type NodeJSON } from 'prosekit/core' +import { + defineCommitRecorder, + type CommitRecorder, +} from 'prosekit/extensions/commit' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +export default function EditorMain(props: { + commitRecorder: CommitRecorder + initialContent?: NodeJSON +}) { + const editor = useMemo(() => { + const extension = union( + defineBasicExtension(), + defineCommitRecorder(props.commitRecorder), + ) + return createEditor({ extension, defaultContent: props.initialContent }) + }, [props.commitRecorder, props.initialContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-change-tracking/src/components/editor/examples/change-tracking/editor.tsx b/react-change-tracking/src/components/editor/examples/change-tracking/editor.tsx new file mode 100644 index 0000000000..131c865c37 --- /dev/null +++ b/react-change-tracking/src/components/editor/examples/change-tracking/editor.tsx @@ -0,0 +1,80 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import type { NodeJSON } from 'prosekit/core' +import { CommitRecorder, type Commit } from 'prosekit/extensions/commit' +import { useCallback, useMemo, useState } from 'react' + +import EditorDiff from './editor-diff' +import EditorMain from './editor-main' + +export default function Editor() { + const [commits, setCommits] = useState< + { id: string; date: Date; commit: Commit }[] + >([]) + const [key, setKey] = useState(0) + const [initialContent, setInitialContent] = useState() + const commitRecorder = useMemo(() => new CommitRecorder(), []) + + const handleCommit = useCallback(() => { + const commit = commitRecorder.commit() + if (!commit) return + const id = Math.random().toString(36).slice(2, 9) + setCommits((commits) => [{ id, date: new Date(), commit }, ...commits]) + }, [commitRecorder]) + + const handleRestore = useCallback( + (id: string) => { + const index = commits.findIndex((commit) => commit.id === id) + const commit = commits[index] + if (index === -1 || !commit) return + const doc = commit.commit.doc + setInitialContent(doc) + setCommits((commits) => commits.slice(index)) + setKey((key) => key + 1) + }, + [commits], + ) + + return ( +
+
+
+ +
+ +
+
+ {commits.map((commit) => ( +
+
+ +
+
+ + {commit.date.toLocaleTimeString()} + + +
+
+ ))} +
+
+ ) +} diff --git a/react-change-tracking/src/components/editor/examples/change-tracking/index.ts b/react-change-tracking/src/components/editor/examples/change-tracking/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-change-tracking/src/components/editor/examples/change-tracking/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-change-tracking/src/main.tsx b/react-change-tracking/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-change-tracking/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-change-tracking/tsconfig.app.json b/react-change-tracking/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-change-tracking/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-change-tracking/tsconfig.json b/react-change-tracking/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-change-tracking/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-change-tracking/tsconfig.node.json b/react-change-tracking/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-change-tracking/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-change-tracking/vite.config.ts b/react-change-tracking/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-change-tracking/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-code-block-themes/.gitignore b/react-code-block-themes/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-code-block-themes/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-code-block-themes/README.md b/react-code-block-themes/README.md new file mode 100644 index 0000000000..586ce662fc --- /dev/null +++ b/react-code-block-themes/README.md @@ -0,0 +1,15 @@ +# react-code-block-themes + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-code-block-themes) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-code-block-themes) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-code-block-themes react-code-block-themes +cd react-code-block-themes +npm install +npm run dev +``` diff --git a/react-code-block-themes/index.html b/react-code-block-themes/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-code-block-themes/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-code-block-themes/package.json b/react-code-block-themes/package.json new file mode 100644 index 0000000000..f1440331b1 --- /dev/null +++ b/react-code-block-themes/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-code-block-themes", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-code-block-themes/src/App.tsx b/react-code-block-themes/src/App.tsx new file mode 100644 index 0000000000..9b93464b4e --- /dev/null +++ b/react-code-block-themes/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code-block-themes' + +export default function App() { + return +} diff --git a/react-code-block-themes/src/app.css b/react-code-block-themes/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-code-block-themes/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx b/react-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx new file mode 100644 index 0000000000..fd5a46a903 --- /dev/null +++ b/react-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-code-block' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/react-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts new file mode 100644 index 0000000000..b5686b8c04 --- /dev/null +++ b/react-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union(defineBasicExtension(), defineCodeBlockView()) +} + +export type EditorExtension = ReturnType diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/react-code-block-themes/src/components/editor/examples/code-block-themes/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-code-block-themes/src/components/editor/examples/code-block-themes/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx b/react-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx new file mode 100644 index 0000000000..264faf038f --- /dev/null +++ b/react-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx @@ -0,0 +1,35 @@ +'use client' + +import { + defineCodeBlockShiki, + shikiBundledThemesInfo, + type ShikiBundledTheme, +} from 'prosekit/extensions/code-block' +import { useExtension } from 'prosekit/react' +import { useMemo, useState } from 'react' + +export function ThemeSelector() { + const [theme, setTheme] = useState('github-dark') + const extension = useMemo(() => { + return defineCodeBlockShiki({ themes: [theme as ShikiBundledTheme] }) + }, [theme]) + useExtension(extension) + + return ( + <> + + + + ) +} diff --git a/react-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx b/react-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx new file mode 100644 index 0000000000..566c98f931 --- /dev/null +++ b/react-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx @@ -0,0 +1,11 @@ +'use client' + +import { ThemeSelector } from './theme-selector' + +export default function Toolbar() { + return ( +
+ +
+ ) +} diff --git a/react-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/react-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/react-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/react-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx b/react-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..f6c0428091 --- /dev/null +++ b/react-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,39 @@ +'use client' + +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { ReactNodeViewProps } from 'prosekit/react' + +export default function CodeBlockView(props: ReactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/react-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/react-code-block-themes/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..b7e6b996bc
--- /dev/null
+++ b/react-code-block-themes/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineReactNodeView,
+  type ReactNodeViewComponent,
+} from 'prosekit/react'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineReactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies ReactNodeViewComponent,
+  })
+}
diff --git a/react-code-block-themes/src/main.tsx b/react-code-block-themes/src/main.tsx
new file mode 100644
index 0000000000..87de8eb52b
--- /dev/null
+++ b/react-code-block-themes/src/main.tsx
@@ -0,0 +1,10 @@
+import './app.css'
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import App from './App.tsx'
+
+ReactDOM.createRoot(document.getElementById('root')!).render(
+  
+    
+  ,
+)
diff --git a/react-code-block-themes/tsconfig.app.json b/react-code-block-themes/tsconfig.app.json
new file mode 100644
index 0000000000..a9b5a59ca6
--- /dev/null
+++ b/react-code-block-themes/tsconfig.app.json
@@ -0,0 +1,28 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "target": "ES2022",
+    "useDefineForClassFields": true,
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "module": "ESNext",
+    "types": ["vite/client"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+    "jsx": "react-jsx",
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["src"]
+}
diff --git a/react-code-block-themes/tsconfig.json b/react-code-block-themes/tsconfig.json
new file mode 100644
index 0000000000..1ffef600d9
--- /dev/null
+++ b/react-code-block-themes/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "files": [],
+  "references": [
+    { "path": "./tsconfig.app.json" },
+    { "path": "./tsconfig.node.json" }
+  ]
+}
diff --git a/react-code-block-themes/tsconfig.node.json b/react-code-block-themes/tsconfig.node.json
new file mode 100644
index 0000000000..8a67f62f4c
--- /dev/null
+++ b/react-code-block-themes/tsconfig.node.json
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "target": "ES2023",
+    "lib": ["ES2023"],
+    "module": "ESNext",
+    "types": ["node"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/react-code-block-themes/vite.config.ts b/react-code-block-themes/vite.config.ts
new file mode 100644
index 0000000000..c90997597d
--- /dev/null
+++ b/react-code-block-themes/vite.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import tailwindcss from '@tailwindcss/vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [react(), tailwindcss()],
+})
diff --git a/react-code-block/.gitignore b/react-code-block/.gitignore
new file mode 100644
index 0000000000..5d6225c6df
--- /dev/null
+++ b/react-code-block/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+.next
+.svelte-kit
diff --git a/react-code-block/README.md b/react-code-block/README.md
new file mode 100644
index 0000000000..eee18c3190
--- /dev/null
+++ b/react-code-block/README.md
@@ -0,0 +1,15 @@
+# react-code-block
+
+A [ProseKit](https://prosekit.dev) example.
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-code-block)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-code-block)
+
+Run the example locally with:
+
+```bash
+npx degit prosekit/examples/react-code-block react-code-block
+cd react-code-block
+npm install
+npm run dev
+```
diff --git a/react-code-block/index.html b/react-code-block/index.html
new file mode 100644
index 0000000000..a5a78f3bf8
--- /dev/null
+++ b/react-code-block/index.html
@@ -0,0 +1,12 @@
+
+
+  
+    
+    
+    ProseKit + React
+  
+  
+    
+ + + diff --git a/react-code-block/package.json b/react-code-block/package.json new file mode 100644 index 0000000000..e09bf534dd --- /dev/null +++ b/react-code-block/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-code-block", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-code-block/src/App.tsx b/react-code-block/src/App.tsx new file mode 100644 index 0000000000..961ce70aad --- /dev/null +++ b/react-code-block/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code-block' + +export default function App() { + return +} diff --git a/react-code-block/src/app.css b/react-code-block/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-code-block/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-code-block/src/components/editor/examples/code-block/editor.tsx b/react-code-block/src/components/editor/examples/code-block/editor.tsx new file mode 100644 index 0000000000..f241113958 --- /dev/null +++ b/react-code-block/src/components/editor/examples/code-block/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-code-block' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-code-block/src/components/editor/examples/code-block/extension.ts b/react-code-block/src/components/editor/examples/code-block/extension.ts new file mode 100644 index 0000000000..099cacf03b --- /dev/null +++ b/react-code-block/src/components/editor/examples/code-block/extension.ts @@ -0,0 +1,24 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { + defineCodeBlock, + defineCodeBlockShiki, +} from 'prosekit/extensions/code-block' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCodeBlock(), + defineCodeBlockShiki(), + defineCodeBlockView(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-code-block/src/components/editor/examples/code-block/index.ts b/react-code-block/src/components/editor/examples/code-block/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-code-block/src/components/editor/examples/code-block/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-code-block/src/components/editor/sample/sample-doc-code-block.ts b/react-code-block/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/react-code-block/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/react-code-block/src/components/editor/ui/button/button.tsx b/react-code-block/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-code-block/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-code-block/src/components/editor/ui/button/index.ts b/react-code-block/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-code-block/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx b/react-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..f6c0428091 --- /dev/null +++ b/react-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,39 @@ +'use client' + +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { ReactNodeViewProps } from 'prosekit/react' + +export default function CodeBlockView(props: ReactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/react-code-block/src/components/editor/ui/code-block-view/index.ts b/react-code-block/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..b7e6b996bc
--- /dev/null
+++ b/react-code-block/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineReactNodeView,
+  type ReactNodeViewComponent,
+} from 'prosekit/react'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineReactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies ReactNodeViewComponent,
+  })
+}
diff --git a/react-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
new file mode 100644
index 0000000000..808361b6ad
--- /dev/null
+++ b/react-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
@@ -0,0 +1,145 @@
+'use client'
+
+import type { Uploader } from 'prosekit/extensions/file'
+import type { ImageExtension } from 'prosekit/extensions/image'
+import { useEditor } from 'prosekit/react'
+import {
+  PopoverPopup,
+  PopoverPositioner,
+  PopoverRoot,
+  PopoverTrigger,
+} from 'prosekit/react/popover'
+import type { OpenChangeEvent } from 'prosekit/web/popover'
+import { useId, useState, type ReactNode } from 'react'
+
+import { Button } from '../button'
+
+export default function ImageUploadPopover(props: {
+  uploader: Uploader
+  tooltip: string
+  disabled: boolean
+  children: ReactNode
+}) {
+  const [open, setOpen] = useState(false)
+  const [url, setUrl] = useState('')
+  const [file, setFile] = useState(null)
+  const ariaId = useId()
+
+  const editor = useEditor()
+
+  const handleFileChange: React.ChangeEventHandler = (
+    event,
+  ) => {
+    const file = event.target.files?.[0]
+
+    if (file) {
+      setFile(file)
+      setUrl('')
+    } else {
+      setFile(null)
+    }
+  }
+
+  const handleUrlChange: React.ChangeEventHandler = (
+    event,
+  ) => {
+    const url = event.target.value
+
+    if (url) {
+      setUrl(url)
+      setFile(null)
+    } else {
+      setUrl('')
+    }
+  }
+
+  const deferResetState = () => {
+    setTimeout(() => {
+      setUrl('')
+      setFile(null)
+    }, 300)
+  }
+
+  const handleSubmit = () => {
+    if (url) {
+      editor.commands.insertImage({ src: url })
+    } else if (file) {
+      editor.commands.uploadImage({ file, uploader: props.uploader })
+    }
+    setOpen(false)
+    deferResetState()
+  }
+
+  const handleOpenChange = (event: OpenChangeEvent) => {
+    if (!event.detail) {
+      deferResetState()
+    }
+    setOpen(event.detail)
+  }
+
+  return (
+    
+      
+        
+      
+
+      
+        
+          {file ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? (
+            
+          ) : null}
+
+          {file ? (
+            
+          ) : null}
+        
+      
+    
+  )
+}
diff --git a/react-code-block/src/components/editor/ui/image-upload-popover/index.ts b/react-code-block/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..5d49d873ce
--- /dev/null
+++ b/react-code-block/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/react-code-block/src/components/editor/ui/toolbar/index.ts b/react-code-block/src/components/editor/ui/toolbar/index.ts
new file mode 100644
index 0000000000..fdf6741e6a
--- /dev/null
+++ b/react-code-block/src/components/editor/ui/toolbar/index.ts
@@ -0,0 +1 @@
+export { default as Toolbar } from './toolbar'
diff --git a/react-code-block/src/components/editor/ui/toolbar/toolbar.tsx b/react-code-block/src/components/editor/ui/toolbar/toolbar.tsx
new file mode 100644
index 0000000000..ce61a2d041
--- /dev/null
+++ b/react-code-block/src/components/editor/ui/toolbar/toolbar.tsx
@@ -0,0 +1,365 @@
+'use client'
+
+import type { BasicExtension } from 'prosekit/basic'
+import type { Editor } from 'prosekit/core'
+import type { Uploader } from 'prosekit/extensions/file'
+import { useEditorDerivedValue } from 'prosekit/react'
+
+import { Button } from '../button'
+import { ImageUploadPopover } from '../image-upload-popover'
+
+function getToolbarItems(editor: Editor) {
+  return {
+    undo: editor.commands.undo
+      ? {
+          isActive: false,
+          canExec: editor.commands.undo.canExec(),
+          command: () => editor.commands.undo(),
+        }
+      : undefined,
+    redo: editor.commands.redo
+      ? {
+          isActive: false,
+          canExec: editor.commands.redo.canExec(),
+          command: () => editor.commands.redo(),
+        }
+      : undefined,
+    bold: editor.commands.toggleBold
+      ? {
+          isActive: editor.marks.bold.isActive(),
+          canExec: editor.commands.toggleBold.canExec(),
+          command: () => editor.commands.toggleBold(),
+        }
+      : undefined,
+    italic: editor.commands.toggleItalic
+      ? {
+          isActive: editor.marks.italic.isActive(),
+          canExec: editor.commands.toggleItalic.canExec(),
+          command: () => editor.commands.toggleItalic(),
+        }
+      : undefined,
+    underline: editor.commands.toggleUnderline
+      ? {
+          isActive: editor.marks.underline.isActive(),
+          canExec: editor.commands.toggleUnderline.canExec(),
+          command: () => editor.commands.toggleUnderline(),
+        }
+      : undefined,
+    strike: editor.commands.toggleStrike
+      ? {
+          isActive: editor.marks.strike.isActive(),
+          canExec: editor.commands.toggleStrike.canExec(),
+          command: () => editor.commands.toggleStrike(),
+        }
+      : undefined,
+    code: editor.commands.toggleCode
+      ? {
+          isActive: editor.marks.code.isActive(),
+          canExec: editor.commands.toggleCode.canExec(),
+          command: () => editor.commands.toggleCode(),
+        }
+      : undefined,
+    codeBlock: editor.commands.insertCodeBlock
+      ? {
+          isActive: editor.nodes.codeBlock.isActive(),
+          canExec: editor.commands.insertCodeBlock.canExec({
+            language: 'javascript',
+          }),
+          command: () =>
+            editor.commands.insertCodeBlock({ language: 'javascript' }),
+        }
+      : undefined,
+    heading1: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 1 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 1 }),
+          command: () => editor.commands.toggleHeading({ level: 1 }),
+        }
+      : undefined,
+    heading2: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 2 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 2 }),
+          command: () => editor.commands.toggleHeading({ level: 2 }),
+        }
+      : undefined,
+    heading3: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 3 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 3 }),
+          command: () => editor.commands.toggleHeading({ level: 3 }),
+        }
+      : undefined,
+    horizontalRule: editor.commands.insertHorizontalRule
+      ? {
+          isActive: editor.nodes.horizontalRule.isActive(),
+          canExec: editor.commands.insertHorizontalRule.canExec(),
+          command: () => editor.commands.insertHorizontalRule(),
+        }
+      : undefined,
+    blockquote: editor.commands.toggleBlockquote
+      ? {
+          isActive: editor.nodes.blockquote.isActive(),
+          canExec: editor.commands.toggleBlockquote.canExec(),
+          command: () => editor.commands.toggleBlockquote(),
+        }
+      : undefined,
+    bulletList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'bullet' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }),
+          command: () => editor.commands.toggleList({ kind: 'bullet' }),
+        }
+      : undefined,
+    orderedList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'ordered' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }),
+          command: () => editor.commands.toggleList({ kind: 'ordered' }),
+        }
+      : undefined,
+    taskList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'task' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'task' }),
+          command: () => editor.commands.toggleList({ kind: 'task' }),
+        }
+      : undefined,
+    toggleList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'toggle' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }),
+          command: () => editor.commands.toggleList({ kind: 'toggle' }),
+        }
+      : undefined,
+    indentList: editor.commands.indentList
+      ? {
+          isActive: false,
+          canExec: editor.commands.indentList.canExec(),
+          command: () => editor.commands.indentList(),
+        }
+      : undefined,
+    dedentList: editor.commands.dedentList
+      ? {
+          isActive: false,
+          canExec: editor.commands.dedentList.canExec(),
+          command: () => editor.commands.dedentList(),
+        }
+      : undefined,
+    insertImage: editor.commands.insertImage
+      ? {
+          isActive: false,
+          canExec: editor.commands.insertImage.canExec(),
+        }
+      : undefined,
+  }
+}
+
+export default function Toolbar(props: { uploader?: Uploader }) {
+  const items = useEditorDerivedValue(getToolbarItems)
+
+  return (
+    
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-code-block/src/main.tsx b/react-code-block/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-code-block/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-code-block/tsconfig.app.json b/react-code-block/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-code-block/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-code-block/tsconfig.json b/react-code-block/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-code-block/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-code-block/tsconfig.node.json b/react-code-block/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-code-block/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-code-block/vite.config.ts b/react-code-block/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-code-block/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-code/.gitignore b/react-code/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-code/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-code/README.md b/react-code/README.md new file mode 100644 index 0000000000..a07555ea9e --- /dev/null +++ b/react-code/README.md @@ -0,0 +1,15 @@ +# react-code + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-code) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-code) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-code react-code +cd react-code +npm install +npm run dev +``` diff --git a/react-code/index.html b/react-code/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-code/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-code/package.json b/react-code/package.json new file mode 100644 index 0000000000..93c51d42b9 --- /dev/null +++ b/react-code/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-code", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-code/src/App.tsx b/react-code/src/App.tsx new file mode 100644 index 0000000000..f2f5d9a360 --- /dev/null +++ b/react-code/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code' + +export default function App() { + return +} diff --git a/react-code/src/app.css b/react-code/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-code/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-code/src/components/editor/examples/code/editor.tsx b/react-code/src/components/editor/examples/code/editor.tsx new file mode 100644 index 0000000000..bef4c5dab0 --- /dev/null +++ b/react-code/src/components/editor/examples/code/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-code' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-code/src/components/editor/examples/code/extension.ts b/react-code/src/components/editor/examples/code/extension.ts new file mode 100644 index 0000000000..e9e273216e --- /dev/null +++ b/react-code/src/components/editor/examples/code/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCode(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-code/src/components/editor/examples/code/index.ts b/react-code/src/components/editor/examples/code/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-code/src/components/editor/examples/code/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-code/src/components/editor/sample/sample-doc-code.ts b/react-code/src/components/editor/sample/sample-doc-code.ts new file mode 100644 index 0000000000..2fdbcee1f3 --- /dev/null +++ b/react-code/src/components/editor/sample/sample-doc-code.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'This is code', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/react-code/src/components/editor/ui/button/button.tsx b/react-code/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-code/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-code/src/components/editor/ui/button/index.ts b/react-code/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-code/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-code/src/components/editor/ui/image-upload-popover/index.ts b/react-code/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-code/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-code/src/components/editor/ui/toolbar/index.ts b/react-code/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-code/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-code/src/components/editor/ui/toolbar/toolbar.tsx b/react-code/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-code/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-code/src/main.tsx b/react-code/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-code/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-code/tsconfig.app.json b/react-code/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-code/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-code/tsconfig.json b/react-code/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-code/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-code/tsconfig.node.json b/react-code/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-code/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-code/vite.config.ts b/react-code/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-code/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-drop-cursor/.gitignore b/react-drop-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-drop-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-drop-cursor/README.md b/react-drop-cursor/README.md new file mode 100644 index 0000000000..c42e139f4c --- /dev/null +++ b/react-drop-cursor/README.md @@ -0,0 +1,15 @@ +# react-drop-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-drop-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-drop-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-drop-cursor react-drop-cursor +cd react-drop-cursor +npm install +npm run dev +``` diff --git a/react-drop-cursor/index.html b/react-drop-cursor/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-drop-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-drop-cursor/package.json b/react-drop-cursor/package.json new file mode 100644 index 0000000000..b37927d1a1 --- /dev/null +++ b/react-drop-cursor/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-drop-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-drop-cursor/src/App.tsx b/react-drop-cursor/src/App.tsx new file mode 100644 index 0000000000..f66459b286 --- /dev/null +++ b/react-drop-cursor/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/drop-cursor' + +export default function App() { + return +} diff --git a/react-drop-cursor/src/app.css b/react-drop-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-drop-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx b/react-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx new file mode 100644 index 0000000000..8dedc17ac0 --- /dev/null +++ b/react-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx @@ -0,0 +1,37 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-drop-cursor' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/react-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts new file mode 100644 index 0000000000..fd79a2c96c --- /dev/null +++ b/react-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts @@ -0,0 +1,23 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineImage(), + defineDropCursor({ + color: false, + width: 4, + class: 'transition-all bg-blue-500', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/react-drop-cursor/src/components/editor/examples/drop-cursor/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-drop-cursor/src/components/editor/examples/drop-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/react-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts new file mode 100644 index 0000000000..22c6b93465 --- /dev/null +++ b/react-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts @@ -0,0 +1,40 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the images below to see the custom drop cursor.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/320x240/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/green/320x240/40', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blue/320x240/187', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/red/320x240/188', + }, + }, + ], +} diff --git a/react-drop-cursor/src/main.tsx b/react-drop-cursor/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-drop-cursor/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-drop-cursor/tsconfig.app.json b/react-drop-cursor/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-drop-cursor/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-drop-cursor/tsconfig.json b/react-drop-cursor/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-drop-cursor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-drop-cursor/tsconfig.node.json b/react-drop-cursor/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-drop-cursor/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-drop-cursor/vite.config.ts b/react-drop-cursor/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-drop-cursor/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-emoji-rules/.gitignore b/react-emoji-rules/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-emoji-rules/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-emoji-rules/README.md b/react-emoji-rules/README.md new file mode 100644 index 0000000000..5a602af6b1 --- /dev/null +++ b/react-emoji-rules/README.md @@ -0,0 +1,15 @@ +# react-emoji-rules + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-emoji-rules) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-emoji-rules) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-emoji-rules react-emoji-rules +cd react-emoji-rules +npm install +npm run dev +``` diff --git a/react-emoji-rules/index.html b/react-emoji-rules/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-emoji-rules/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-emoji-rules/package.json b/react-emoji-rules/package.json new file mode 100644 index 0000000000..93e259cdab --- /dev/null +++ b/react-emoji-rules/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-emoji-rules", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-emoji-rules/src/App.tsx b/react-emoji-rules/src/App.tsx new file mode 100644 index 0000000000..1e4ef54fd6 --- /dev/null +++ b/react-emoji-rules/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/emoji-rules' + +export default function App() { + return +} diff --git a/react-emoji-rules/src/app.css b/react-emoji-rules/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-emoji-rules/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx b/react-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx new file mode 100644 index 0000000000..c17d11fd22 --- /dev/null +++ b/react-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx @@ -0,0 +1,30 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/react-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts new file mode 100644 index 0000000000..5cac9cbc79 --- /dev/null +++ b/react-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts @@ -0,0 +1,15 @@ +import { defineEnterRule } from 'prosekit/extensions/enter-rule' + +/** + * Converts the text before the text cursor into an emoji when pressing `Enter`. + */ +export function defineEmojiEnterRule() { + return defineEnterRule({ + regex: /:(apple|banana):$/, + handler: ({ match, from, to, state }) => { + const text = match[1] as 'apple' | 'banana' + const emoji = text === 'apple' ? '🍎' : '🍌' + return state.tr.replaceWith(from, to, state.schema.text(emoji)) + }, + }) +} diff --git a/react-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/react-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts new file mode 100644 index 0000000000..bc9bcb8412 --- /dev/null +++ b/react-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts @@ -0,0 +1,15 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { defineEmojiEnterRule } from './emoji' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineEmojiEnterRule(), + definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/react-emoji-rules/src/components/editor/examples/emoji-rules/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-emoji-rules/src/components/editor/examples/emoji-rules/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-emoji-rules/src/main.tsx b/react-emoji-rules/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-emoji-rules/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-emoji-rules/tsconfig.app.json b/react-emoji-rules/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-emoji-rules/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-emoji-rules/tsconfig.json b/react-emoji-rules/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-emoji-rules/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-emoji-rules/tsconfig.node.json b/react-emoji-rules/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-emoji-rules/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-emoji-rules/vite.config.ts b/react-emoji-rules/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-emoji-rules/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-full/.gitignore b/react-full/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-full/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-full/README.md b/react-full/README.md new file mode 100644 index 0000000000..cbe69d8c6e --- /dev/null +++ b/react-full/README.md @@ -0,0 +1,15 @@ +# react-full + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-full) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-full) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-full react-full +cd react-full +npm install +npm run dev +``` diff --git a/react-full/index.html b/react-full/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-full/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-full/package.json b/react-full/package.json new file mode 100644 index 0000000000..4c57997be8 --- /dev/null +++ b/react-full/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-react-full", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-full/src/App.tsx b/react-full/src/App.tsx new file mode 100644 index 0000000000..c93bd3a429 --- /dev/null +++ b/react-full/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/full' + +export default function App() { + return +} diff --git a/react-full/src/app.css b/react-full/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-full/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-full/src/components/editor/examples/full/editor.tsx b/react-full/src/components/editor/examples/full/editor.tsx new file mode 100644 index 0000000000..d49fac1be9 --- /dev/null +++ b/react-full/src/components/editor/examples/full/editor.tsx @@ -0,0 +1,56 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-full' +import { tags } from '../../sample/sample-tag-data' +import { sampleUploader } from '../../sample/sample-uploader' +import { users } from '../../sample/sample-user-data' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' +import { InlineMenu } from '../../ui/inline-menu' +import { SlashMenu } from '../../ui/slash-menu' +import { TableHandle } from '../../ui/table-handle' +import { TagMenu } from '../../ui/tag-menu' +import { Toolbar } from '../../ui/toolbar' +import { UserMenu } from '../../ui/user-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+ + + + + + + +
+
+
+ ) +} diff --git a/react-full/src/components/editor/examples/full/extension.ts b/react-full/src/components/editor/examples/full/extension.ts new file mode 100644 index 0000000000..5fc2f60685 --- /dev/null +++ b/react-full/src/components/editor/examples/full/extension.ts @@ -0,0 +1,34 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineImageUploadHandler } from 'prosekit/extensions/image' +import { defineMath } from 'prosekit/extensions/math' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' +import { sampleUploader } from '../../sample/sample-uploader' +import { defineCodeBlockView } from '../../ui/code-block-view' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + defineMention(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + defineCodeBlockShiki(), + defineHorizontalRule(), + defineCodeBlockView(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-full/src/components/editor/examples/full/html.ts b/react-full/src/components/editor/examples/full/html.ts new file mode 100644 index 0000000000..4945ec9108 --- /dev/null +++ b/react-full/src/components/editor/examples/full/html.ts @@ -0,0 +1,35 @@ +import { createEditor, type NodeJSON } from 'prosekit/core' + +import { sampleContent } from '../../sample/sample-doc-full' + +import { defineExtension } from './extension' + +/** + * Renders a ProseMirror document JSON object to an HTML string. + * + * This is useful for server-side rendering. + * + * @example + * + * ```js + * import { JSDOM } from 'jsdom' + * const dom = new JSDOM('') + * const document = dom.window.document + * const html = renderHTML(document, myContentJSON) + * ``` + */ +export function renderHTML( + document: Document, + content: NodeJSON = sampleContent, +): string { + const extension = defineExtension() + const editor = createEditor({ extension }) + editor.setContent(content) + const html: string = editor.getDocHTML({ document }) + if (html.startsWith('
') && html.endsWith('
')) { + return html.slice(5, -6) // Remove the wrapping
tags + } else { + console.error('Unexpected HTML format: expected a single
wrapper') + return html + } +} diff --git a/react-full/src/components/editor/examples/full/index.ts b/react-full/src/components/editor/examples/full/index.ts new file mode 100644 index 0000000000..516b54a1f0 --- /dev/null +++ b/react-full/src/components/editor/examples/full/index.ts @@ -0,0 +1,2 @@ +export { default as ExampleEditor } from './editor' +export { renderHTML } from './html' diff --git a/react-full/src/components/editor/sample/katex.ts b/react-full/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/react-full/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/react-full/src/components/editor/sample/sample-doc-full.ts b/react-full/src/components/editor/sample/sample-doc-full.ts new file mode 100644 index 0000000000..13e49b634d --- /dev/null +++ b/react-full/src/components/editor/sample/sample-doc-full.ts @@ -0,0 +1,442 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'The editor that thinks like you' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', + }, + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'writing without barriers', + }, + { type: 'text', text: '.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Text that shines.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Make your words ' }, + { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, + { type: 'text', text: ', or ' }, + { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, + { type: 'text', text: '. Add ' }, + { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, + { type: 'text', text: ' that stands out. Create ' }, + { + type: 'text', + marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], + text: 'links', + }, + { type: 'text', text: ' that connect.' }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Select any text to format it. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '@' }, + { type: 'text', text: ' to mention ' }, + { + type: 'mention', + attrs: { id: '39', value: '@someone', kind: 'user' }, + }, + { type: 'text', text: ' or ' }, + { type: 'text', marks: [{ type: 'code' }], text: '#' }, + { type: 'text', text: ' for ' }, + { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, + { type: 'text', text: '. Press ' }, + { type: 'text', marks: [{ type: 'code' }], text: '/' }, + { type: 'text', text: " and discover what's possible." }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Lists that organize.' }], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Bullet points that guide thoughts' }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Nested lists for complex ideas' }], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sub-points flow naturally' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Tasks that focus' }], + }, + { + type: 'list', + attrs: { kind: 'task', order: null, checked: true, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Done feels good' }], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Todo drives action' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Numbered steps' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sequential thinking' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Clear progress' }], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Code that inspires.' }], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Images that captivate.' }], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/season/320x240/107', + }, + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the handle in the bottom right corner to resize.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Tables that structure.' }], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'Feature', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'How to use', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Format text' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Select and choose' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Perfect styling' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Add mentions' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Type @ and name' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Connected ideas' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Insert anything' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Press / for menu' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Endless possibilities' }], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Math that renders.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Inline math like ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' appears within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Quotes that inspire.' }], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: '"This is not just an editor. This is how writing should feel."', + }, + ], + }, + ], + }, + { type: 'horizontalRule' }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Start typing. Everything else just flows.' }, + ], + }, + ], +} diff --git a/react-full/src/components/editor/sample/sample-tag-data.ts b/react-full/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/react-full/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/react-full/src/components/editor/sample/sample-uploader.ts b/react-full/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/react-full/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/react-full/src/components/editor/sample/sample-user-data.ts b/react-full/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/react-full/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/react-full/src/components/editor/ui/block-handle/block-handle.tsx b/react-full/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..3cc6028d5c --- /dev/null +++ b/react-full/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,33 @@ +'use client' + +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/react/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/react-full/src/components/editor/ui/block-handle/index.ts b/react-full/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/react-full/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/react-full/src/components/editor/ui/button/button.tsx b/react-full/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-full/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-full/src/components/editor/ui/button/index.ts b/react-full/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-full/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-full/src/components/editor/ui/code-block-view/code-block-view.tsx b/react-full/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..f6c0428091 --- /dev/null +++ b/react-full/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,39 @@ +'use client' + +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { ReactNodeViewProps } from 'prosekit/react' + +export default function CodeBlockView(props: ReactNodeViewProps) { + const attrs = props.node.attrs as CodeBlockAttrs + const language = attrs.language + + const setLanguage = (language: string) => { + const attrs: CodeBlockAttrs = { language } + props.setAttrs(attrs) + } + + return ( + <> +
+ +
+

+    
+  )
+}
diff --git a/react-full/src/components/editor/ui/code-block-view/index.ts b/react-full/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..b7e6b996bc
--- /dev/null
+++ b/react-full/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineReactNodeView,
+  type ReactNodeViewComponent,
+} from 'prosekit/react'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineReactNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies ReactNodeViewComponent,
+  })
+}
diff --git a/react-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/react-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
new file mode 100644
index 0000000000..87c1746622
--- /dev/null
+++ b/react-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
@@ -0,0 +1,7 @@
+'use client'
+
+import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator'
+
+export default function DropIndicator() {
+  return 
+}
diff --git a/react-full/src/components/editor/ui/drop-indicator/index.ts b/react-full/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..f8fb7139c4
--- /dev/null
+++ b/react-full/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator'
diff --git a/react-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
new file mode 100644
index 0000000000..808361b6ad
--- /dev/null
+++ b/react-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
@@ -0,0 +1,145 @@
+'use client'
+
+import type { Uploader } from 'prosekit/extensions/file'
+import type { ImageExtension } from 'prosekit/extensions/image'
+import { useEditor } from 'prosekit/react'
+import {
+  PopoverPopup,
+  PopoverPositioner,
+  PopoverRoot,
+  PopoverTrigger,
+} from 'prosekit/react/popover'
+import type { OpenChangeEvent } from 'prosekit/web/popover'
+import { useId, useState, type ReactNode } from 'react'
+
+import { Button } from '../button'
+
+export default function ImageUploadPopover(props: {
+  uploader: Uploader
+  tooltip: string
+  disabled: boolean
+  children: ReactNode
+}) {
+  const [open, setOpen] = useState(false)
+  const [url, setUrl] = useState('')
+  const [file, setFile] = useState(null)
+  const ariaId = useId()
+
+  const editor = useEditor()
+
+  const handleFileChange: React.ChangeEventHandler = (
+    event,
+  ) => {
+    const file = event.target.files?.[0]
+
+    if (file) {
+      setFile(file)
+      setUrl('')
+    } else {
+      setFile(null)
+    }
+  }
+
+  const handleUrlChange: React.ChangeEventHandler = (
+    event,
+  ) => {
+    const url = event.target.value
+
+    if (url) {
+      setUrl(url)
+      setFile(null)
+    } else {
+      setUrl('')
+    }
+  }
+
+  const deferResetState = () => {
+    setTimeout(() => {
+      setUrl('')
+      setFile(null)
+    }, 300)
+  }
+
+  const handleSubmit = () => {
+    if (url) {
+      editor.commands.insertImage({ src: url })
+    } else if (file) {
+      editor.commands.uploadImage({ file, uploader: props.uploader })
+    }
+    setOpen(false)
+    deferResetState()
+  }
+
+  const handleOpenChange = (event: OpenChangeEvent) => {
+    if (!event.detail) {
+      deferResetState()
+    }
+    setOpen(event.detail)
+  }
+
+  return (
+    
+      
+        
+      
+
+      
+        
+          {file ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? null : (
+            <>
+              
+              
+            
+          )}
+
+          {url ? (
+            
+          ) : null}
+
+          {file ? (
+            
+          ) : null}
+        
+      
+    
+  )
+}
diff --git a/react-full/src/components/editor/ui/image-upload-popover/index.ts b/react-full/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..5d49d873ce
--- /dev/null
+++ b/react-full/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/react-full/src/components/editor/ui/image-view/image-view.tsx b/react-full/src/components/editor/ui/image-view/image-view.tsx
new file mode 100644
index 0000000000..06da475774
--- /dev/null
+++ b/react-full/src/components/editor/ui/image-view/image-view.tsx
@@ -0,0 +1,94 @@
+'use client'
+
+import { UploadTask } from 'prosekit/extensions/file'
+import type { ImageAttrs } from 'prosekit/extensions/image'
+import type { ReactNodeViewProps } from 'prosekit/react'
+import { ResizableHandle, ResizableRoot } from 'prosekit/react/resizable'
+import { useEffect, useState, type SyntheticEvent } from 'react'
+
+export default function ImageView(props: ReactNodeViewProps) {
+  const attrs = props.node.attrs as ImageAttrs
+  const url = attrs.src || ''
+  const uploading = url.startsWith('blob:')
+
+  const [aspectRatio, setAspectRatio] = useState()
+  const [error, setError] = useState()
+  const [progress, setProgress] = useState(0)
+
+  useEffect(() => {
+    if (!uploading) return
+
+    const uploadTask = UploadTask.get(url)
+    if (!uploadTask) return
+
+    let canceled = false
+
+    uploadTask.finished.catch((error) => {
+      if (canceled) return
+      setError(String(error))
+    })
+    const unsubscribeProgress = uploadTask.subscribeProgress(
+      ({ loaded, total }) => {
+        if (canceled) return
+        setProgress(total ? loaded / total : 0)
+      },
+    )
+
+    return () => {
+      canceled = true
+      unsubscribeProgress()
+    }
+  }, [url, uploading])
+
+  const handleImageLoad = (event: SyntheticEvent) => {
+    const img = event.target as HTMLImageElement
+    const { naturalWidth, naturalHeight } = img
+    const ratio = naturalWidth / naturalHeight
+    if (ratio && Number.isFinite(ratio)) {
+      setAspectRatio(ratio)
+    }
+    if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) {
+      props.setAttrs({ width: naturalWidth, height: naturalHeight })
+    }
+  }
+
+  return (
+     props.setAttrs(event.detail)}
+      data-selected={props.selected ? '' : undefined}
+      className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid"
+    >
+      {url && !error && (
+        upload preview
+      )}
+      {uploading && !error && (
+        
+
+
{Math.round(progress * 100)}%
+
+ )} + {error && ( +
+
+
+ Failed to upload image +
+
+ )} + +
+
+
+ ) +} diff --git a/react-full/src/components/editor/ui/image-view/index.ts b/react-full/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..c4a95f9d3f --- /dev/null +++ b/react-full/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + defineReactNodeView, + type ReactNodeViewComponent, +} from 'prosekit/react' + +import ImageView from './image-view' + +export function defineImageView(): Extension { + return defineReactNodeView({ + name: 'image', + component: ImageView satisfies ReactNodeViewComponent, + }) +} diff --git a/react-full/src/components/editor/ui/inline-menu/index.ts b/react-full/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/react-full/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/react-full/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-full/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..af1b2bb2b7 --- /dev/null +++ b/react-full/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/react' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/react/inline-popover' +import { useState } from 'react' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/react-full/src/components/editor/ui/slash-menu/index.ts b/react-full/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/react-full/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/react-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/react-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..d0dca0934a --- /dev/null +++ b/react-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,11 @@ +'use client' + +import { AutocompleteEmpty } from 'prosekit/react/autocomplete' + +export default function SlashMenuEmpty() { + return ( + + No results + + ) +} diff --git a/react-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/react-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..349c6e8924 --- /dev/null +++ b/react-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,23 @@ +'use client' + +import { AutocompleteItem } from 'prosekit/react/autocomplete' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}) { + return ( + + {props.label} + {props.kbd && ( + + {props.kbd} + + )} + + ) +} diff --git a/react-full/src/components/editor/ui/slash-menu/slash-menu.tsx b/react-full/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..3738f51aab --- /dev/null +++ b/react-full/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,102 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/react' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor.commands.setParagraph()} + /> + + editor.commands.setHeading({ level: 1 })} + /> + + editor.commands.setHeading({ level: 2 })} + /> + + editor.commands.setHeading({ level: 3 })} + /> + + editor.commands.wrapInList({ kind: 'bullet' })} + /> + + editor.commands.wrapInList({ kind: 'ordered' })} + /> + + editor.commands.wrapInList({ kind: 'task' })} + /> + + editor.commands.wrapInList({ kind: 'toggle' })} + /> + + editor.commands.setBlockquote()} + /> + + editor.commands.insertTable({ row: 3, col: 3 })} + /> + + editor.commands.insertHorizontalRule()} + /> + + editor.commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/react-full/src/components/editor/ui/table-handle/index.ts b/react-full/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/react-full/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/react-full/src/components/editor/ui/table-handle/table-handle.tsx b/react-full/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..b90b351382 --- /dev/null +++ b/react-full/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,188 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/react' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/react/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/react/table-handle' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props) { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + {state.addTableColumnBefore.canExec && ( + + Insert Left + + )} + {state.addTableColumnAfter.canExec && ( + + Insert Right + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableColumn.canExec && ( + + Delete Column + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+ + + + +
+
+ + + {state.addTableRowAbove.canExec && ( + + Insert Above + + )} + {state.addTableRowBelow.canExec && ( + + Insert Below + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableRow.canExec && ( + + Delete Row + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+
+ ) +} diff --git a/react-full/src/components/editor/ui/tag-menu/index.ts b/react-full/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..d344b33a70 --- /dev/null +++ b/react-full/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu' diff --git a/react-full/src/components/editor/ui/tag-menu/tag-menu.tsx b/react-full/src/components/editor/ui/tag-menu/tag-menu.tsx new file mode 100644 index 0000000000..711486fcf7 --- /dev/null +++ b/react-full/src/components/editor/ui/tag-menu/tag-menu.tsx @@ -0,0 +1,54 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/react' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +const regex = /#[\da-z]*$/i + +export default function TagMenu(props: { + tags: { id: number; label: string }[] +}) { + const editor = useEditor>() + + const handleTagInsert = (id: number, label: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '#' + label, + kind: 'tag', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + + + +
+ + No results + + + {props.tags.map((tag) => ( + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + ))} +
+
+
+
+ ) +} diff --git a/react-full/src/components/editor/ui/toolbar/index.ts b/react-full/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-full/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-full/src/components/editor/ui/toolbar/toolbar.tsx b/react-full/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-full/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-full/src/components/editor/ui/user-menu/index.ts b/react-full/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/react-full/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/react-full/src/components/editor/ui/user-menu/user-menu.tsx b/react-full/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..46555f6382 --- /dev/null +++ b/react-full/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,64 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/react' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}) { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + {props.users.map((user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + ))} +
+
+
+
+ ) +} diff --git a/react-full/src/main.tsx b/react-full/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-full/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-full/tsconfig.app.json b/react-full/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-full/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-full/tsconfig.json b/react-full/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-full/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-full/tsconfig.node.json b/react-full/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-full/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-full/vite.config.ts b/react-full/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-full/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-gap-cursor/.gitignore b/react-gap-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-gap-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-gap-cursor/README.md b/react-gap-cursor/README.md new file mode 100644 index 0000000000..5e1f3e1da1 --- /dev/null +++ b/react-gap-cursor/README.md @@ -0,0 +1,15 @@ +# react-gap-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-gap-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-gap-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-gap-cursor react-gap-cursor +cd react-gap-cursor +npm install +npm run dev +``` diff --git a/react-gap-cursor/index.html b/react-gap-cursor/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-gap-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-gap-cursor/package.json b/react-gap-cursor/package.json new file mode 100644 index 0000000000..8a75ab110b --- /dev/null +++ b/react-gap-cursor/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-gap-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-gap-cursor/src/App.tsx b/react-gap-cursor/src/App.tsx new file mode 100644 index 0000000000..ed7e74417e --- /dev/null +++ b/react-gap-cursor/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/gap-cursor' + +export default function App() { + return +} diff --git a/react-gap-cursor/src/app.css b/react-gap-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-gap-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx b/react-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx new file mode 100644 index 0000000000..9b852f4ad5 --- /dev/null +++ b/react-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx @@ -0,0 +1,36 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-gap-cursor' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + return createEditor({ extension: defineExtension(), defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/react-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts new file mode 100644 index 0000000000..599497170d --- /dev/null +++ b/react-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts @@ -0,0 +1,19 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineGapCursor(), + defineImage(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/react-gap-cursor/src/components/editor/examples/gap-cursor/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-gap-cursor/src/components/editor/examples/gap-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/react-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts new file mode 100644 index 0000000000..e40ee2a83b --- /dev/null +++ b/react-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts @@ -0,0 +1,28 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + ], +} diff --git a/react-gap-cursor/src/main.tsx b/react-gap-cursor/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-gap-cursor/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-gap-cursor/tsconfig.app.json b/react-gap-cursor/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-gap-cursor/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-gap-cursor/tsconfig.json b/react-gap-cursor/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-gap-cursor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-gap-cursor/tsconfig.node.json b/react-gap-cursor/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-gap-cursor/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-gap-cursor/vite.config.ts b/react-gap-cursor/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-gap-cursor/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-hard-break/.gitignore b/react-hard-break/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-hard-break/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-hard-break/README.md b/react-hard-break/README.md new file mode 100644 index 0000000000..551adf5370 --- /dev/null +++ b/react-hard-break/README.md @@ -0,0 +1,15 @@ +# react-hard-break + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-hard-break) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-hard-break) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-hard-break react-hard-break +cd react-hard-break +npm install +npm run dev +``` diff --git a/react-hard-break/index.html b/react-hard-break/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-hard-break/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-hard-break/package.json b/react-hard-break/package.json new file mode 100644 index 0000000000..6cfba6d0b1 --- /dev/null +++ b/react-hard-break/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-hard-break", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-hard-break/src/App.tsx b/react-hard-break/src/App.tsx new file mode 100644 index 0000000000..db3ea90c2a --- /dev/null +++ b/react-hard-break/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/hard-break' + +export default function App() { + return +} diff --git a/react-hard-break/src/app.css b/react-hard-break/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-hard-break/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-hard-break/src/components/editor/examples/hard-break/editor.tsx b/react-hard-break/src/components/editor/examples/hard-break/editor.tsx new file mode 100644 index 0000000000..62f3f272c1 --- /dev/null +++ b/react-hard-break/src/components/editor/examples/hard-break/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-hard-break' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-hard-break/src/components/editor/examples/hard-break/extension.ts b/react-hard-break/src/components/editor/examples/hard-break/extension.ts new file mode 100644 index 0000000000..cad2881056 --- /dev/null +++ b/react-hard-break/src/components/editor/examples/hard-break/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHardBreak } from 'prosekit/extensions/hard-break' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHardBreak(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-hard-break/src/components/editor/examples/hard-break/index.ts b/react-hard-break/src/components/editor/examples/hard-break/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-hard-break/src/components/editor/examples/hard-break/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-hard-break/src/components/editor/examples/hard-break/toolbar.tsx b/react-hard-break/src/components/editor/examples/hard-break/toolbar.tsx new file mode 100644 index 0000000000..784e685064 --- /dev/null +++ b/react-hard-break/src/components/editor/examples/hard-break/toolbar.tsx @@ -0,0 +1,33 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + hardBreak: { + canExec: editor.commands.insertHardBreak.canExec(), + command: () => editor.commands.insertHardBreak(), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/react-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/react-hard-break/src/components/editor/sample/sample-doc-hard-break.ts new file mode 100644 index 0000000000..e1c9786b72 --- /dev/null +++ b/react-hard-break/src/components/editor/sample/sample-doc-hard-break.ts @@ -0,0 +1,68 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: "O'er all the hilltops", + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Is quiet now,', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'In all the treetops', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hearest thou', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hardly a breath;', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'The birds are asleep in the trees:', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Wait, soon like these', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Thou too shalt rest.', + }, + { + type: 'hardBreak', + }, + ], + }, + ], +} diff --git a/react-hard-break/src/components/editor/ui/button/button.tsx b/react-hard-break/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-hard-break/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-hard-break/src/components/editor/ui/button/index.ts b/react-hard-break/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-hard-break/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-hard-break/src/main.tsx b/react-hard-break/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-hard-break/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-hard-break/tsconfig.app.json b/react-hard-break/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-hard-break/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-hard-break/tsconfig.json b/react-hard-break/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-hard-break/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-hard-break/tsconfig.node.json b/react-hard-break/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-hard-break/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-hard-break/vite.config.ts b/react-hard-break/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-hard-break/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-heading/.gitignore b/react-heading/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-heading/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-heading/README.md b/react-heading/README.md new file mode 100644 index 0000000000..0d3635b951 --- /dev/null +++ b/react-heading/README.md @@ -0,0 +1,15 @@ +# react-heading + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-heading) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-heading) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-heading react-heading +cd react-heading +npm install +npm run dev +``` diff --git a/react-heading/index.html b/react-heading/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-heading/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-heading/package.json b/react-heading/package.json new file mode 100644 index 0000000000..601ac32532 --- /dev/null +++ b/react-heading/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-heading", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-heading/src/App.tsx b/react-heading/src/App.tsx new file mode 100644 index 0000000000..c70e72d05f --- /dev/null +++ b/react-heading/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/heading' + +export default function App() { + return +} diff --git a/react-heading/src/app.css b/react-heading/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-heading/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-heading/src/components/editor/examples/heading/editor.tsx b/react-heading/src/components/editor/examples/heading/editor.tsx new file mode 100644 index 0000000000..e1d392e168 --- /dev/null +++ b/react-heading/src/components/editor/examples/heading/editor.tsx @@ -0,0 +1,38 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-heading' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + return createEditor({ extension: defineExtension(), defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-heading/src/components/editor/examples/heading/extension.ts b/react-heading/src/components/editor/examples/heading/extension.ts new file mode 100644 index 0000000000..e4f8e6ace0 --- /dev/null +++ b/react-heading/src/components/editor/examples/heading/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHeading(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-heading/src/components/editor/examples/heading/index.ts b/react-heading/src/components/editor/examples/heading/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-heading/src/components/editor/examples/heading/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-heading/src/components/editor/sample/sample-doc-heading.ts b/react-heading/src/components/editor/sample/sample-doc-heading.ts new file mode 100644 index 0000000000..210497e633 --- /dev/null +++ b/react-heading/src/components/editor/sample/sample-doc-heading.ts @@ -0,0 +1,23 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'H1' }], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'H2' }], + }, + { + type: 'heading', + attrs: { level: 3 }, + content: [{ type: 'text', text: 'H3' }], + }, + { type: 'paragraph', content: [] }, + ], +} diff --git a/react-heading/src/components/editor/ui/button/button.tsx b/react-heading/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-heading/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-heading/src/components/editor/ui/button/index.ts b/react-heading/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-heading/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-heading/src/components/editor/ui/image-upload-popover/index.ts b/react-heading/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-heading/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-heading/src/components/editor/ui/toolbar/index.ts b/react-heading/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-heading/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-heading/src/components/editor/ui/toolbar/toolbar.tsx b/react-heading/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-heading/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-heading/src/main.tsx b/react-heading/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-heading/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-heading/tsconfig.app.json b/react-heading/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-heading/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-heading/tsconfig.json b/react-heading/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-heading/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-heading/tsconfig.node.json b/react-heading/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-heading/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-heading/vite.config.ts b/react-heading/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-heading/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-highlight/.gitignore b/react-highlight/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-highlight/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-highlight/README.md b/react-highlight/README.md new file mode 100644 index 0000000000..b2c083a7f6 --- /dev/null +++ b/react-highlight/README.md @@ -0,0 +1,15 @@ +# react-highlight + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-highlight) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-highlight) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-highlight react-highlight +cd react-highlight +npm install +npm run dev +``` diff --git a/react-highlight/index.html b/react-highlight/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-highlight/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-highlight/package.json b/react-highlight/package.json new file mode 100644 index 0000000000..5b2ee80a01 --- /dev/null +++ b/react-highlight/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-highlight", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-highlight/src/App.tsx b/react-highlight/src/App.tsx new file mode 100644 index 0000000000..2509b001f7 --- /dev/null +++ b/react-highlight/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/highlight' + +export default function App() { + return +} diff --git a/react-highlight/src/app.css b/react-highlight/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-highlight/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-highlight/src/components/editor/examples/highlight/editor.tsx b/react-highlight/src/components/editor/examples/highlight/editor.tsx new file mode 100644 index 0000000000..f49a0436dc --- /dev/null +++ b/react-highlight/src/components/editor/examples/highlight/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-highlight' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-highlight/src/components/editor/examples/highlight/extension.ts b/react-highlight/src/components/editor/examples/highlight/extension.ts new file mode 100644 index 0000000000..abc131c3be --- /dev/null +++ b/react-highlight/src/components/editor/examples/highlight/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHighlight } from 'prosekit/extensions/highlight' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHighlight(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-highlight/src/components/editor/examples/highlight/index.ts b/react-highlight/src/components/editor/examples/highlight/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-highlight/src/components/editor/examples/highlight/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-highlight/src/components/editor/examples/highlight/toolbar.tsx b/react-highlight/src/components/editor/examples/highlight/toolbar.tsx new file mode 100644 index 0000000000..13681ed44c --- /dev/null +++ b/react-highlight/src/components/editor/examples/highlight/toolbar.tsx @@ -0,0 +1,34 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + highlight: { + isActive: editor.marks.highlight.isActive(), + canExec: editor.commands.toggleHighlight.canExec(), + command: () => editor.commands.toggleHighlight(), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/react-highlight/src/components/editor/sample/sample-doc-highlight.ts b/react-highlight/src/components/editor/sample/sample-doc-highlight.ts new file mode 100644 index 0000000000..0de1a1f7b2 --- /dev/null +++ b/react-highlight/src/components/editor/sample/sample-doc-highlight.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'highlight', + }, + ], + text: 'This is highlighted text', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/react-highlight/src/components/editor/ui/button/button.tsx b/react-highlight/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-highlight/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-highlight/src/components/editor/ui/button/index.ts b/react-highlight/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-highlight/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-highlight/src/main.tsx b/react-highlight/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-highlight/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-highlight/tsconfig.app.json b/react-highlight/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-highlight/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-highlight/tsconfig.json b/react-highlight/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-highlight/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-highlight/tsconfig.node.json b/react-highlight/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-highlight/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-highlight/vite.config.ts b/react-highlight/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-highlight/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-horizontal-rule/.gitignore b/react-horizontal-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-horizontal-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-horizontal-rule/README.md b/react-horizontal-rule/README.md new file mode 100644 index 0000000000..c7c1993944 --- /dev/null +++ b/react-horizontal-rule/README.md @@ -0,0 +1,15 @@ +# react-horizontal-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-horizontal-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-horizontal-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-horizontal-rule react-horizontal-rule +cd react-horizontal-rule +npm install +npm run dev +``` diff --git a/react-horizontal-rule/index.html b/react-horizontal-rule/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-horizontal-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-horizontal-rule/package.json b/react-horizontal-rule/package.json new file mode 100644 index 0000000000..115b5221c5 --- /dev/null +++ b/react-horizontal-rule/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-horizontal-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-horizontal-rule/src/App.tsx b/react-horizontal-rule/src/App.tsx new file mode 100644 index 0000000000..974e387364 --- /dev/null +++ b/react-horizontal-rule/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/horizontal-rule' + +export default function App() { + return +} diff --git a/react-horizontal-rule/src/app.css b/react-horizontal-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-horizontal-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx new file mode 100644 index 0000000000..cbf25168cf --- /dev/null +++ b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx @@ -0,0 +1,32 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + return createEditor({ extension: defineExtension() }) + }, []) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts new file mode 100644 index 0000000000..49b6121eeb --- /dev/null +++ b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHorizontalRule(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-horizontal-rule/src/components/editor/ui/button/button.tsx b/react-horizontal-rule/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-horizontal-rule/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-horizontal-rule/src/components/editor/ui/button/index.ts b/react-horizontal-rule/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-horizontal-rule/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/react-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/react-horizontal-rule/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-horizontal-rule/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx b/react-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-horizontal-rule/src/main.tsx b/react-horizontal-rule/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-horizontal-rule/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-horizontal-rule/tsconfig.app.json b/react-horizontal-rule/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-horizontal-rule/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-horizontal-rule/tsconfig.json b/react-horizontal-rule/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-horizontal-rule/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-horizontal-rule/tsconfig.node.json b/react-horizontal-rule/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-horizontal-rule/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-horizontal-rule/vite.config.ts b/react-horizontal-rule/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-horizontal-rule/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-image-view/.gitignore b/react-image-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-image-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-image-view/README.md b/react-image-view/README.md new file mode 100644 index 0000000000..82f4507524 --- /dev/null +++ b/react-image-view/README.md @@ -0,0 +1,15 @@ +# react-image-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-image-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-image-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-image-view react-image-view +cd react-image-view +npm install +npm run dev +``` diff --git a/react-image-view/index.html b/react-image-view/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-image-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-image-view/package.json b/react-image-view/package.json new file mode 100644 index 0000000000..af1217ed4e --- /dev/null +++ b/react-image-view/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-image-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-image-view/src/App.tsx b/react-image-view/src/App.tsx new file mode 100644 index 0000000000..46ede58891 --- /dev/null +++ b/react-image-view/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/image-view' + +export default function App() { + return +} diff --git a/react-image-view/src/app.css b/react-image-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-image-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-image-view/src/components/editor/examples/image-view/editor.tsx b/react-image-view/src/components/editor/examples/image-view/editor.tsx new file mode 100644 index 0000000000..a0bb6d3f1e --- /dev/null +++ b/react-image-view/src/components/editor/examples/image-view/editor.tsx @@ -0,0 +1,37 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-image' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-image-view/src/components/editor/examples/image-view/extension.ts b/react-image-view/src/components/editor/examples/image-view/extension.ts new file mode 100644 index 0000000000..a21febf634 --- /dev/null +++ b/react-image-view/src/components/editor/examples/image-view/extension.ts @@ -0,0 +1,18 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineImageUploadHandler } from 'prosekit/extensions/image' + +import { sampleUploader } from '../../sample/sample-uploader' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-image-view/src/components/editor/examples/image-view/index.ts b/react-image-view/src/components/editor/examples/image-view/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-image-view/src/components/editor/examples/image-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-image-view/src/components/editor/sample/sample-doc-image.ts b/react-image-view/src/components/editor/sample/sample-doc-image.ts new file mode 100644 index 0000000000..c97628339d --- /dev/null +++ b/react-image-view/src/components/editor/sample/sample-doc-image.ts @@ -0,0 +1,32 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Paste or drop an image to upload it.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/white/200x200/1', + width: 160, + height: 160, + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/640x360/42', + width: 240, + height: 135, + }, + }, + ], +} diff --git a/react-image-view/src/components/editor/sample/sample-uploader.ts b/react-image-view/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/react-image-view/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/react-image-view/src/components/editor/ui/image-view/image-view.tsx b/react-image-view/src/components/editor/ui/image-view/image-view.tsx new file mode 100644 index 0000000000..06da475774 --- /dev/null +++ b/react-image-view/src/components/editor/ui/image-view/image-view.tsx @@ -0,0 +1,94 @@ +'use client' + +import { UploadTask } from 'prosekit/extensions/file' +import type { ImageAttrs } from 'prosekit/extensions/image' +import type { ReactNodeViewProps } from 'prosekit/react' +import { ResizableHandle, ResizableRoot } from 'prosekit/react/resizable' +import { useEffect, useState, type SyntheticEvent } from 'react' + +export default function ImageView(props: ReactNodeViewProps) { + const attrs = props.node.attrs as ImageAttrs + const url = attrs.src || '' + const uploading = url.startsWith('blob:') + + const [aspectRatio, setAspectRatio] = useState() + const [error, setError] = useState() + const [progress, setProgress] = useState(0) + + useEffect(() => { + if (!uploading) return + + const uploadTask = UploadTask.get(url) + if (!uploadTask) return + + let canceled = false + + uploadTask.finished.catch((error) => { + if (canceled) return + setError(String(error)) + }) + const unsubscribeProgress = uploadTask.subscribeProgress( + ({ loaded, total }) => { + if (canceled) return + setProgress(total ? loaded / total : 0) + }, + ) + + return () => { + canceled = true + unsubscribeProgress() + } + }, [url, uploading]) + + const handleImageLoad = (event: SyntheticEvent) => { + const img = event.target as HTMLImageElement + const { naturalWidth, naturalHeight } = img + const ratio = naturalWidth / naturalHeight + if (ratio && Number.isFinite(ratio)) { + setAspectRatio(ratio) + } + if (naturalWidth && naturalHeight && (!attrs.width || !attrs.height)) { + props.setAttrs({ width: naturalWidth, height: naturalHeight }) + } + } + + return ( + props.setAttrs(event.detail)} + data-selected={props.selected ? '' : undefined} + className="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid" + > + {url && !error && ( + upload preview + )} + {uploading && !error && ( +
+
+
{Math.round(progress * 100)}%
+
+ )} + {error && ( +
+
+
+ Failed to upload image +
+
+ )} + +
+
+
+ ) +} diff --git a/react-image-view/src/components/editor/ui/image-view/index.ts b/react-image-view/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..c4a95f9d3f --- /dev/null +++ b/react-image-view/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + defineReactNodeView, + type ReactNodeViewComponent, +} from 'prosekit/react' + +import ImageView from './image-view' + +export function defineImageView(): Extension { + return defineReactNodeView({ + name: 'image', + component: ImageView satisfies ReactNodeViewComponent, + }) +} diff --git a/react-image-view/src/main.tsx b/react-image-view/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-image-view/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-image-view/tsconfig.app.json b/react-image-view/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-image-view/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-image-view/tsconfig.json b/react-image-view/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-image-view/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-image-view/tsconfig.node.json b/react-image-view/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-image-view/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-image-view/vite.config.ts b/react-image-view/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-image-view/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-inline-menu/.gitignore b/react-inline-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-inline-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-inline-menu/README.md b/react-inline-menu/README.md new file mode 100644 index 0000000000..7aef3d6362 --- /dev/null +++ b/react-inline-menu/README.md @@ -0,0 +1,15 @@ +# react-inline-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-inline-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-inline-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-inline-menu react-inline-menu +cd react-inline-menu +npm install +npm run dev +``` diff --git a/react-inline-menu/index.html b/react-inline-menu/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-inline-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-inline-menu/package.json b/react-inline-menu/package.json new file mode 100644 index 0000000000..fa45986e6e --- /dev/null +++ b/react-inline-menu/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-inline-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-inline-menu/src/App.tsx b/react-inline-menu/src/App.tsx new file mode 100644 index 0000000000..660285db3c --- /dev/null +++ b/react-inline-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/inline-menu' + +export default function App() { + return +} diff --git a/react-inline-menu/src/app.css b/react-inline-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-inline-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-inline-menu/src/components/editor/examples/inline-menu/editor.tsx b/react-inline-menu/src/components/editor/examples/inline-menu/editor.tsx new file mode 100644 index 0000000000..7a23947606 --- /dev/null +++ b/react-inline-menu/src/components/editor/examples/inline-menu/editor.tsx @@ -0,0 +1,38 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-inline-menu' +import { InlineMenu } from '../../ui/inline-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + return createEditor({ extension: defineExtension(), defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/react-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/react-inline-menu/src/components/editor/examples/inline-menu/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/react-inline-menu/src/components/editor/examples/inline-menu/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/react-inline-menu/src/components/editor/examples/inline-menu/index.ts b/react-inline-menu/src/components/editor/examples/inline-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-inline-menu/src/components/editor/examples/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/react-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts new file mode 100644 index 0000000000..62a5984cb0 --- /dev/null +++ b/react-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts @@ -0,0 +1,33 @@ +import type { NodeJSON } from 'prosekit/core' + +const loremText = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'Try to select some text', + }, + ], + }, + ...Array.from({ length: 10 }, () => ({ + type: 'paragraph' as const, + content: [ + { + type: 'text' as const, + text: loremText, + }, + ], + })), + ], +} diff --git a/react-inline-menu/src/components/editor/ui/button/button.tsx b/react-inline-menu/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-inline-menu/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-inline-menu/src/components/editor/ui/button/index.ts b/react-inline-menu/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-inline-menu/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-inline-menu/src/components/editor/ui/inline-menu/index.ts b/react-inline-menu/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/react-inline-menu/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/react-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..af1b2bb2b7 --- /dev/null +++ b/react-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/react' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/react/inline-popover' +import { useState } from 'react' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/react-inline-menu/src/main.tsx b/react-inline-menu/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-inline-menu/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-inline-menu/tsconfig.app.json b/react-inline-menu/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-inline-menu/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-inline-menu/tsconfig.json b/react-inline-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-inline-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-inline-menu/tsconfig.node.json b/react-inline-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-inline-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-inline-menu/vite.config.ts b/react-inline-menu/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-inline-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-italic/.gitignore b/react-italic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-italic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-italic/README.md b/react-italic/README.md new file mode 100644 index 0000000000..1412b917f5 --- /dev/null +++ b/react-italic/README.md @@ -0,0 +1,15 @@ +# react-italic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-italic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-italic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-italic react-italic +cd react-italic +npm install +npm run dev +``` diff --git a/react-italic/index.html b/react-italic/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-italic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-italic/package.json b/react-italic/package.json new file mode 100644 index 0000000000..d04ce3bd6d --- /dev/null +++ b/react-italic/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-italic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-italic/src/App.tsx b/react-italic/src/App.tsx new file mode 100644 index 0000000000..7ce968b449 --- /dev/null +++ b/react-italic/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/italic' + +export default function App() { + return +} diff --git a/react-italic/src/app.css b/react-italic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-italic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-italic/src/components/editor/examples/italic/editor.tsx b/react-italic/src/components/editor/examples/italic/editor.tsx new file mode 100644 index 0000000000..5651947320 --- /dev/null +++ b/react-italic/src/components/editor/examples/italic/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-italic' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-italic/src/components/editor/examples/italic/extension.ts b/react-italic/src/components/editor/examples/italic/extension.ts new file mode 100644 index 0000000000..a456b06aad --- /dev/null +++ b/react-italic/src/components/editor/examples/italic/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineItalic(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-italic/src/components/editor/examples/italic/index.ts b/react-italic/src/components/editor/examples/italic/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-italic/src/components/editor/examples/italic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-italic/src/components/editor/sample/sample-doc-italic.ts b/react-italic/src/components/editor/sample/sample-doc-italic.ts new file mode 100644 index 0000000000..fb99415b2c --- /dev/null +++ b/react-italic/src/components/editor/sample/sample-doc-italic.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/react-italic/src/components/editor/ui/button/button.tsx b/react-italic/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-italic/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-italic/src/components/editor/ui/button/index.ts b/react-italic/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-italic/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-italic/src/components/editor/ui/image-upload-popover/index.ts b/react-italic/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-italic/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-italic/src/components/editor/ui/toolbar/index.ts b/react-italic/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-italic/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-italic/src/components/editor/ui/toolbar/toolbar.tsx b/react-italic/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-italic/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-italic/src/main.tsx b/react-italic/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-italic/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-italic/tsconfig.app.json b/react-italic/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-italic/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-italic/tsconfig.json b/react-italic/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-italic/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-italic/tsconfig.node.json b/react-italic/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-italic/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-italic/vite.config.ts b/react-italic/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-italic/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-katex/.gitignore b/react-katex/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-katex/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-katex/README.md b/react-katex/README.md new file mode 100644 index 0000000000..eade88a0db --- /dev/null +++ b/react-katex/README.md @@ -0,0 +1,15 @@ +# react-katex + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-katex) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-katex) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-katex react-katex +cd react-katex +npm install +npm run dev +``` diff --git a/react-katex/index.html b/react-katex/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-katex/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-katex/package.json b/react-katex/package.json new file mode 100644 index 0000000000..635c9b2517 --- /dev/null +++ b/react-katex/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-react-katex", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-katex/src/App.tsx b/react-katex/src/App.tsx new file mode 100644 index 0000000000..2a28c7c7d7 --- /dev/null +++ b/react-katex/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/katex' + +export default function App() { + return +} diff --git a/react-katex/src/app.css b/react-katex/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-katex/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-katex/src/components/editor/examples/katex/editor.tsx b/react-katex/src/components/editor/examples/katex/editor.tsx new file mode 100644 index 0000000000..41d22fcbde --- /dev/null +++ b/react-katex/src/components/editor/examples/katex/editor.tsx @@ -0,0 +1,37 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-tex' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-katex/src/components/editor/examples/katex/extension.ts b/react-katex/src/components/editor/examples/katex/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/react-katex/src/components/editor/examples/katex/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-katex/src/components/editor/examples/katex/index.ts b/react-katex/src/components/editor/examples/katex/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-katex/src/components/editor/examples/katex/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-katex/src/components/editor/sample/katex.ts b/react-katex/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/react-katex/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/react-katex/src/components/editor/sample/sample-doc-tex.ts b/react-katex/src/components/editor/sample/sample-doc-tex.ts new file mode 100644 index 0000000000..21ccf3e94e --- /dev/null +++ b/react-katex/src/components/editor/sample/sample-doc-tex.ts @@ -0,0 +1,60 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Inline equations' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Block equations' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: 'The Gaussian integral:' }], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + ], +} diff --git a/react-katex/src/main.tsx b/react-katex/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-katex/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-katex/tsconfig.app.json b/react-katex/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-katex/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-katex/tsconfig.json b/react-katex/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-katex/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-katex/tsconfig.node.json b/react-katex/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-katex/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-katex/vite.config.ts b/react-katex/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-katex/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-keymap/.gitignore b/react-keymap/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-keymap/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-keymap/README.md b/react-keymap/README.md new file mode 100644 index 0000000000..a1dd4b7b45 --- /dev/null +++ b/react-keymap/README.md @@ -0,0 +1,15 @@ +# react-keymap + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-keymap) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-keymap) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-keymap react-keymap +cd react-keymap +npm install +npm run dev +``` diff --git a/react-keymap/index.html b/react-keymap/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-keymap/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-keymap/package.json b/react-keymap/package.json new file mode 100644 index 0000000000..1d7d027b27 --- /dev/null +++ b/react-keymap/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-keymap", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-keymap/src/App.tsx b/react-keymap/src/App.tsx new file mode 100644 index 0000000000..da3b6ebb09 --- /dev/null +++ b/react-keymap/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/keymap' + +export default function App() { + return +} diff --git a/react-keymap/src/app.css b/react-keymap/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-keymap/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-keymap/src/components/editor/examples/keymap/editor.tsx b/react-keymap/src/components/editor/examples/keymap/editor.tsx new file mode 100644 index 0000000000..00bc32b314 --- /dev/null +++ b/react-keymap/src/components/editor/examples/keymap/editor.tsx @@ -0,0 +1,54 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useCallback, useMemo, useState } from 'react' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + const [submissions, setSubmissions] = useState([]) + + const pushSubmission = useCallback( + (hotkey: string) => { + const docString = JSON.stringify(editor.getDocJSON()) + const submission = `${new Date().toISOString()}\t${hotkey}\n${docString}` + setSubmissions((prev) => [...prev, submission]) + }, + [editor], + ) + + return ( + +
+ +
+
+
+
+
+ Submit Records +
    + {submissions.map((submission, index) => ( +
  1. +
    {submission}
    +
  2. + ))} +
+ {submissions.length === 0 &&
No submissions yet
} +
+
+ ) +} diff --git a/react-keymap/src/components/editor/examples/keymap/extension.ts b/react-keymap/src/components/editor/examples/keymap/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/react-keymap/src/components/editor/examples/keymap/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/react-keymap/src/components/editor/examples/keymap/index.ts b/react-keymap/src/components/editor/examples/keymap/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-keymap/src/components/editor/examples/keymap/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-keymap/src/components/editor/examples/keymap/toolbar.tsx b/react-keymap/src/components/editor/examples/keymap/toolbar.tsx new file mode 100644 index 0000000000..d76e237a60 --- /dev/null +++ b/react-keymap/src/components/editor/examples/keymap/toolbar.tsx @@ -0,0 +1,29 @@ +'use client' + +import { useState } from 'react' + +import { Button } from '../../ui/button' + +import { useSubmitKeymap } from './use-submit-keymap' + +export default function Toolbar(props: { onSubmit: (hotkey: string) => void }) { + const [hotkey, setHotkey] = useState<'Shift-Enter' | 'Enter'>('Shift-Enter') + useSubmitKeymap(hotkey, props.onSubmit) + + return ( +
+ + + +
+ ) +} diff --git a/react-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts b/react-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts new file mode 100644 index 0000000000..a163d7ebba --- /dev/null +++ b/react-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts @@ -0,0 +1,19 @@ +import type { Keymap } from 'prosekit/core' +import { useKeymap } from 'prosekit/react' +import { useMemo } from 'react' + +export function useSubmitKeymap( + hotkey: 'Shift-Enter' | 'Enter', + onSubmit: (hotkey: string) => void, +) { + const keymap: Keymap = useMemo(() => { + return { + [hotkey]: () => { + onSubmit(hotkey) + return true + }, + } + }, [hotkey, onSubmit]) + + useKeymap(keymap) +} diff --git a/react-keymap/src/components/editor/ui/button/button.tsx b/react-keymap/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-keymap/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-keymap/src/components/editor/ui/button/index.ts b/react-keymap/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-keymap/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-keymap/src/main.tsx b/react-keymap/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-keymap/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-keymap/tsconfig.app.json b/react-keymap/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-keymap/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-keymap/tsconfig.json b/react-keymap/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-keymap/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-keymap/tsconfig.node.json b/react-keymap/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-keymap/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-keymap/vite.config.ts b/react-keymap/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-keymap/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-link-mark-view/.gitignore b/react-link-mark-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-link-mark-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-link-mark-view/README.md b/react-link-mark-view/README.md new file mode 100644 index 0000000000..d160af1a3c --- /dev/null +++ b/react-link-mark-view/README.md @@ -0,0 +1,15 @@ +# react-link-mark-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-link-mark-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-link-mark-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-link-mark-view react-link-mark-view +cd react-link-mark-view +npm install +npm run dev +``` diff --git a/react-link-mark-view/index.html b/react-link-mark-view/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-link-mark-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-link-mark-view/package.json b/react-link-mark-view/package.json new file mode 100644 index 0000000000..c5fd61a1bb --- /dev/null +++ b/react-link-mark-view/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-link-mark-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-link-mark-view/src/App.tsx b/react-link-mark-view/src/App.tsx new file mode 100644 index 0000000000..8a8685678d --- /dev/null +++ b/react-link-mark-view/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/link-mark-view' + +export default function App() { + return +} diff --git a/react-link-mark-view/src/app.css b/react-link-mark-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-link-mark-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx b/react-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx new file mode 100644 index 0000000000..a78baa04e1 --- /dev/null +++ b/react-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx @@ -0,0 +1,37 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-link-mark-view' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/react-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts new file mode 100644 index 0000000000..697375ed00 --- /dev/null +++ b/react-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineReactMarkView } from 'prosekit/react' + +import LinkView from './link-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineReactMarkView({ + name: 'link', + component: LinkView, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/react-link-mark-view/src/components/editor/examples/link-mark-view/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-link-mark-view/src/components/editor/examples/link-mark-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx b/react-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx new file mode 100644 index 0000000000..9a87078d64 --- /dev/null +++ b/react-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx @@ -0,0 +1,47 @@ +'use client' + +import type { ReactMarkViewProps } from 'prosekit/react' +import { useEffect, useState } from 'react' + +const colors = [ + '#f06292', + '#ba68c8', + '#9575cd', + '#7986cb', + '#64b5f6', + '#4fc3f7', + '#4dd0e1', + '#4db6ac', + '#81c784', + '#aed581', + '#ffb74d', + '#ffa726', + '#ff8a65', + '#d4e157', + '#ffd54f', + '#ffecb3', +] + +function pickRandomColor() { + return colors[Math.floor(Math.random() * colors.length)] +} + +export default function Link(props: ReactMarkViewProps) { + const [color, setColor] = useState(colors[0]) + const href = props.mark.attrs.href as string + + useEffect(() => { + const interval = setInterval(() => { + setColor(pickRandomColor()) + }, 1000) + return () => clearInterval(interval) + }, []) + + return ( + + ) +} diff --git a/react-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/react-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts new file mode 100644 index 0000000000..57abd09dd6 --- /dev/null +++ b/react-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is a link that changes color every second: ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/react-link-mark-view/src/main.tsx b/react-link-mark-view/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-link-mark-view/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-link-mark-view/tsconfig.app.json b/react-link-mark-view/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-link-mark-view/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-link-mark-view/tsconfig.json b/react-link-mark-view/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-link-mark-view/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-link-mark-view/tsconfig.node.json b/react-link-mark-view/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-link-mark-view/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-link-mark-view/vite.config.ts b/react-link-mark-view/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-link-mark-view/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-link/.gitignore b/react-link/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-link/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-link/README.md b/react-link/README.md new file mode 100644 index 0000000000..4eb974fbe0 --- /dev/null +++ b/react-link/README.md @@ -0,0 +1,15 @@ +# react-link + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-link) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-link) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-link react-link +cd react-link +npm install +npm run dev +``` diff --git a/react-link/index.html b/react-link/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-link/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-link/package.json b/react-link/package.json new file mode 100644 index 0000000000..488fda2dfe --- /dev/null +++ b/react-link/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-link", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-link/src/App.tsx b/react-link/src/App.tsx new file mode 100644 index 0000000000..1cf0f24636 --- /dev/null +++ b/react-link/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/link' + +export default function App() { + return +} diff --git a/react-link/src/app.css b/react-link/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-link/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-link/src/components/editor/examples/link/editor.tsx b/react-link/src/components/editor/examples/link/editor.tsx new file mode 100644 index 0000000000..8d9fc1bee4 --- /dev/null +++ b/react-link/src/components/editor/examples/link/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-link' +import { InlineMenu } from '../../ui/inline-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/react-link/src/components/editor/examples/link/extension.ts b/react-link/src/components/editor/examples/link/extension.ts new file mode 100644 index 0000000000..bf499147da --- /dev/null +++ b/react-link/src/components/editor/examples/link/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLink } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-link/src/components/editor/examples/link/index.ts b/react-link/src/components/editor/examples/link/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-link/src/components/editor/examples/link/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-link/src/components/editor/sample/sample-doc-link.ts b/react-link/src/components/editor/sample/sample-doc-link.ts new file mode 100644 index 0000000000..726cf334fd --- /dev/null +++ b/react-link/src/components/editor/sample/sample-doc-link.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is an ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/react-link/src/components/editor/ui/button/button.tsx b/react-link/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-link/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-link/src/components/editor/ui/button/index.ts b/react-link/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-link/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-link/src/components/editor/ui/inline-menu/index.ts b/react-link/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/react-link/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/react-link/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-link/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..af1b2bb2b7 --- /dev/null +++ b/react-link/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/react' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/react/inline-popover' +import { useState } from 'react' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/react-link/src/main.tsx b/react-link/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-link/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-link/tsconfig.app.json b/react-link/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-link/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-link/tsconfig.json b/react-link/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-link/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-link/tsconfig.node.json b/react-link/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-link/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-link/vite.config.ts b/react-link/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-link/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-list-custom-checkbox/.gitignore b/react-list-custom-checkbox/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-list-custom-checkbox/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-list-custom-checkbox/README.md b/react-list-custom-checkbox/README.md new file mode 100644 index 0000000000..9de808f76b --- /dev/null +++ b/react-list-custom-checkbox/README.md @@ -0,0 +1,15 @@ +# react-list-custom-checkbox + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-list-custom-checkbox) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-list-custom-checkbox) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-list-custom-checkbox react-list-custom-checkbox +cd react-list-custom-checkbox +npm install +npm run dev +``` diff --git a/react-list-custom-checkbox/index.html b/react-list-custom-checkbox/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-list-custom-checkbox/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-list-custom-checkbox/package.json b/react-list-custom-checkbox/package.json new file mode 100644 index 0000000000..3d12f2f11d --- /dev/null +++ b/react-list-custom-checkbox/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-list-custom-checkbox", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-list-custom-checkbox/src/App.tsx b/react-list-custom-checkbox/src/App.tsx new file mode 100644 index 0000000000..96b82e9a84 --- /dev/null +++ b/react-list-custom-checkbox/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/list-custom-checkbox' + +export default function App() { + return +} diff --git a/react-list-custom-checkbox/src/app.css b/react-list-custom-checkbox/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-list-custom-checkbox/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css new file mode 100644 index 0000000000..ec631b72ad --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css @@ -0,0 +1,75 @@ +div[data-custom-list-css-enabled] + .ProseMirror + .prosemirror-flat-list[data-list-kind='task'] { + & > .list-marker label { + box-sizing: border-box; + display: flex; + position: relative; + left: calc(var(--spacing) * -0.5); + align-items: center; + cursor: pointer; + transition: transform 0.15s ease-in-out; + + &:hover { + transform: scale(1.1); + } + + &::after { + position: absolute; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + content: ''; + color: var(--color-white); + opacity: 0; + } + + /* https://api.iconify.design/lucide.css?icons=check */ + &::after { + display: inline-block; + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); + } + + & input { + box-sizing: border-box; + appearance: none; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + margin: 0; + border-width: 1px; + border-style: solid; + border-radius: var(--radius-md); + border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); + box-shadow: var(--shadow-sm); + cursor: pointer; + transition: all 0.15s ease-in-out; + + &:hover { + box-shadow: var(--shadow-md); + } + + &:checked { + border-color: var(--color-red-500); + background-color: var(--color-red-500); + } + } + } + + &[data-list-checked] > .list-marker label { + &::after { + opacity: 1; + } + } + + &[data-list-checked] { + color: var(--color-gray-400); + text-decoration: line-through; + text-decoration-color: var(--color-gray-400); + } +} diff --git a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx new file mode 100644 index 0000000000..c9765e7bd6 --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx @@ -0,0 +1,46 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import './custom-list.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-list-custom-checkbox' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ + extension, + defaultContent, + }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/react-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts new file mode 100644 index 0000000000..972611aed1 --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts @@ -0,0 +1,38 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', + }, + { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, + { type: 'text', text: ' for the styles.' }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Completed Task' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Incomplete Task' }], + }, + ], + }, + ], +} diff --git a/react-list-custom-checkbox/src/components/editor/ui/button/button.tsx b/react-list-custom-checkbox/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-list-custom-checkbox/src/components/editor/ui/button/index.ts b/react-list-custom-checkbox/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/react-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx b/react-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-list-custom-checkbox/src/main.tsx b/react-list-custom-checkbox/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-list-custom-checkbox/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-list-custom-checkbox/tsconfig.app.json b/react-list-custom-checkbox/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-list-custom-checkbox/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-list-custom-checkbox/tsconfig.json b/react-list-custom-checkbox/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-list-custom-checkbox/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-list-custom-checkbox/tsconfig.node.json b/react-list-custom-checkbox/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-list-custom-checkbox/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-list-custom-checkbox/vite.config.ts b/react-list-custom-checkbox/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-list-custom-checkbox/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-list/.gitignore b/react-list/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-list/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-list/README.md b/react-list/README.md new file mode 100644 index 0000000000..f79af22497 --- /dev/null +++ b/react-list/README.md @@ -0,0 +1,15 @@ +# react-list + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-list) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-list) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-list react-list +cd react-list +npm install +npm run dev +``` diff --git a/react-list/index.html b/react-list/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-list/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-list/package.json b/react-list/package.json new file mode 100644 index 0000000000..da7a569c15 --- /dev/null +++ b/react-list/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-list", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-list/src/App.tsx b/react-list/src/App.tsx new file mode 100644 index 0000000000..73f050ef0c --- /dev/null +++ b/react-list/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/list' + +export default function App() { + return +} diff --git a/react-list/src/app.css b/react-list/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-list/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-list/src/components/editor/examples/list/editor.tsx b/react-list/src/components/editor/examples/list/editor.tsx new file mode 100644 index 0000000000..89a19a2a23 --- /dev/null +++ b/react-list/src/components/editor/examples/list/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-list' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-list/src/components/editor/examples/list/extension.ts b/react-list/src/components/editor/examples/list/extension.ts new file mode 100644 index 0000000000..f66bae6ff7 --- /dev/null +++ b/react-list/src/components/editor/examples/list/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineList } from 'prosekit/extensions/list' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineList(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-list/src/components/editor/examples/list/index.ts b/react-list/src/components/editor/examples/list/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-list/src/components/editor/examples/list/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-list/src/components/editor/sample/sample-doc-list.ts b/react-list/src/components/editor/sample/sample-doc-list.ts new file mode 100644 index 0000000000..091bc37185 --- /dev/null +++ b/react-list/src/components/editor/sample/sample-doc-list.ts @@ -0,0 +1,47 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Ordered List' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'toggle', collapsed: true }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, + { + type: 'list', + attrs: { + kind: 'bullet', + }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, + ], + }, + ], + }, + ], +} diff --git a/react-list/src/components/editor/ui/button/button.tsx b/react-list/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-list/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-list/src/components/editor/ui/button/index.ts b/react-list/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-list/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-list/src/components/editor/ui/image-upload-popover/index.ts b/react-list/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-list/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-list/src/components/editor/ui/toolbar/index.ts b/react-list/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-list/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-list/src/components/editor/ui/toolbar/toolbar.tsx b/react-list/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-list/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-list/src/main.tsx b/react-list/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-list/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-list/tsconfig.app.json b/react-list/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-list/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-list/tsconfig.json b/react-list/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-list/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-list/tsconfig.node.json b/react-list/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-list/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-list/vite.config.ts b/react-list/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-list/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-loro/.gitignore b/react-loro/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-loro/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-loro/README.md b/react-loro/README.md new file mode 100644 index 0000000000..94ed80130d --- /dev/null +++ b/react-loro/README.md @@ -0,0 +1,15 @@ +# react-loro + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-loro) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-loro) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-loro react-loro +cd react-loro +npm install +npm run dev +``` diff --git a/react-loro/index.html b/react-loro/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-loro/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-loro/package.json b/react-loro/package.json new file mode 100644 index 0000000000..1c553d0ba3 --- /dev/null +++ b/react-loro/package.json @@ -0,0 +1,31 @@ +{ + "name": "example-react-loro", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "loro-crdt": "^1.12.1", + "loro-prosemirror": "^0.4.3", + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-wasm": "^3.6.0" + } +} diff --git a/react-loro/src/App.tsx b/react-loro/src/App.tsx new file mode 100644 index 0000000000..71d2a6b080 --- /dev/null +++ b/react-loro/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/loro' + +export default function App() { + return +} diff --git a/react-loro/src/app.css b/react-loro/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-loro/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-loro/src/components/editor/examples/loro/editor-component.tsx b/react-loro/src/components/editor/examples/loro/editor-component.tsx new file mode 100644 index 0000000000..e6df130c78 --- /dev/null +++ b/react-loro/src/components/editor/examples/loro/editor-component.tsx @@ -0,0 +1,38 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/loro/style.css' + +import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function EditorComponent(props: { + loro: LoroDocType + awareness: CursorAwareness +}) { + const editor = useMemo(() => { + const extension = defineExtension(props.loro, props.awareness) + return createEditor({ extension }) + }, [props.loro, props.awareness]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-loro/src/components/editor/examples/loro/editor.tsx b/react-loro/src/components/editor/examples/loro/editor.tsx new file mode 100644 index 0000000000..5357d78b68 --- /dev/null +++ b/react-loro/src/components/editor/examples/loro/editor.tsx @@ -0,0 +1,65 @@ +'use client' + +import { LoroDoc, type AwarenessListener } from 'loro-crdt' +import { CursorAwareness, type LoroDocType } from 'loro-prosemirror' +import { useEffect, useState } from 'react' + +import EditorComponent from './editor-component' + +export default function Page() { + const { loroA, awarenessA, loroB, awarenessB } = useLoroDocs() + + return ( +
+ + +
+ ) +} + +function useLoroDocs() { + const [loroState] = useState(() => { + const loroA: LoroDocType = new LoroDoc() + const loroB: LoroDocType = new LoroDoc() + + const idA = loroA.peerIdStr + const idB = loroB.peerIdStr + + const awarenessA = new CursorAwareness(idA) + const awarenessB = new CursorAwareness(idB) + + return { loroA, loroB, idA, idB, awarenessA, awarenessB } + }) + + useEffect(() => { + const { loroA, loroB, idA, idB, awarenessA, awarenessB } = loroState + loroA.import(loroB.export({ mode: 'update' })) + loroB.import(loroA.export({ mode: 'update' })) + const unsubscribeA = loroA.subscribeLocalUpdates((updates) => { + loroB.import(updates) + }) + const unsubscribeB = loroB.subscribeLocalUpdates((updates) => { + loroA.import(updates) + }) + const awarenessAListener: AwarenessListener = (_, origin) => { + if (origin === 'local') { + awarenessB.apply(awarenessA.encode([idA])) + } + } + const awarenessBListener: AwarenessListener = (_, origin) => { + if (origin === 'local') { + awarenessA.apply(awarenessB.encode([idB])) + } + } + awarenessA.addListener(awarenessAListener) + awarenessB.addListener(awarenessBListener) + return () => { + awarenessA.removeListener(awarenessAListener) + awarenessB.removeListener(awarenessBListener) + unsubscribeA() + unsubscribeB() + } + }, [loroState]) + + return loroState +} diff --git a/react-loro/src/components/editor/examples/loro/extension.ts b/react-loro/src/components/editor/examples/loro/extension.ts new file mode 100644 index 0000000000..5a85c5e168 --- /dev/null +++ b/react-loro/src/components/editor/examples/loro/extension.ts @@ -0,0 +1,47 @@ +import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineLoro } from 'prosekit/extensions/loro' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { + return union([ + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineLoro({ doc, awareness }), + ]) +} + +export type EditorExtension = ReturnType diff --git a/react-loro/src/components/editor/examples/loro/index.ts b/react-loro/src/components/editor/examples/loro/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-loro/src/components/editor/examples/loro/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-loro/src/components/editor/ui/button/button.tsx b/react-loro/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-loro/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-loro/src/components/editor/ui/button/index.ts b/react-loro/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-loro/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-loro/src/components/editor/ui/image-upload-popover/index.ts b/react-loro/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-loro/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-loro/src/components/editor/ui/toolbar/index.ts b/react-loro/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-loro/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-loro/src/components/editor/ui/toolbar/toolbar.tsx b/react-loro/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-loro/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-loro/src/main.tsx b/react-loro/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-loro/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-loro/tsconfig.app.json b/react-loro/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-loro/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-loro/tsconfig.json b/react-loro/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-loro/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-loro/tsconfig.node.json b/react-loro/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-loro/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-loro/vite.config.ts b/react-loro/vite.config.ts new file mode 100644 index 0000000000..fb354b9350 --- /dev/null +++ b/react-loro/vite.config.ts @@ -0,0 +1,9 @@ +import wasm from 'vite-plugin-wasm' +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [wasm(), react(), tailwindcss()], +}) diff --git a/react-mark-rule/.gitignore b/react-mark-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-mark-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-mark-rule/README.md b/react-mark-rule/README.md new file mode 100644 index 0000000000..a3e59a6610 --- /dev/null +++ b/react-mark-rule/README.md @@ -0,0 +1,15 @@ +# react-mark-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-mark-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-mark-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-mark-rule react-mark-rule +cd react-mark-rule +npm install +npm run dev +``` diff --git a/react-mark-rule/index.html b/react-mark-rule/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-mark-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-mark-rule/package.json b/react-mark-rule/package.json new file mode 100644 index 0000000000..5ef046547d --- /dev/null +++ b/react-mark-rule/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-mark-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-mark-rule/src/App.tsx b/react-mark-rule/src/App.tsx new file mode 100644 index 0000000000..4e93a4bf60 --- /dev/null +++ b/react-mark-rule/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/mark-rule' + +export default function App() { + return +} diff --git a/react-mark-rule/src/app.css b/react-mark-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-mark-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-mark-rule/src/components/editor/examples/mark-rule/editor.tsx b/react-mark-rule/src/components/editor/examples/mark-rule/editor.tsx new file mode 100644 index 0000000000..c17d11fd22 --- /dev/null +++ b/react-mark-rule/src/components/editor/examples/mark-rule/editor.tsx @@ -0,0 +1,30 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/react-mark-rule/src/components/editor/examples/mark-rule/extension.ts new file mode 100644 index 0000000000..4a1de40783 --- /dev/null +++ b/react-mark-rule/src/components/editor/examples/mark-rule/extension.ts @@ -0,0 +1,32 @@ +import { + defineBaseCommands, + defineBaseKeymap, + defineHistory, + union, +} from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { definePlaceholder } from 'prosekit/extensions/placeholder' +import { defineText } from 'prosekit/extensions/text' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +import { defineIssueLink } from './issue-link' + +export function defineExtension() { + return union( + defineDoc(), + defineText(), + defineParagraph(), + defineHistory(), + defineBaseKeymap(), + defineBaseCommands(), + defineVirtualSelection(), + defineLinkSpec(), + defineLinkMarkRule(), + definePlaceholder({ placeholder: 'Try typing #123' }), + defineIssueLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-mark-rule/src/components/editor/examples/mark-rule/index.ts b/react-mark-rule/src/components/editor/examples/mark-rule/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-mark-rule/src/components/editor/examples/mark-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/react-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts new file mode 100644 index 0000000000..3840b5e53d --- /dev/null +++ b/react-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts @@ -0,0 +1,32 @@ +import { defineMarkSpec, union } from 'prosekit/core' +import { defineMarkRule } from 'prosekit/extensions/mark-rule' + +export function defineIssueLink() { + return union( + defineMarkSpec({ + name: 'issueLink', + inclusive: false, + attrs: { + issueNumber: {}, + }, + toDOM(node) { + const issueNumber = node.attrs.issueNumber as number + return [ + 'a', + { + href: `https://example.com/issues/${issueNumber}`, + title: `Issue #${issueNumber}`, + }, + 0, + ] + }, + }), + defineMarkRule({ + regex: /#(\d+)/g, + type: 'issueLink', + attrs: (match) => { + return { issueNumber: Number.parseInt(match[1] || '0') } + }, + }), + ) +} diff --git a/react-mark-rule/src/main.tsx b/react-mark-rule/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-mark-rule/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-mark-rule/tsconfig.app.json b/react-mark-rule/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-mark-rule/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-mark-rule/tsconfig.json b/react-mark-rule/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-mark-rule/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-mark-rule/tsconfig.node.json b/react-mark-rule/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-mark-rule/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-mark-rule/vite.config.ts b/react-mark-rule/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-mark-rule/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-minimal/.gitignore b/react-minimal/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-minimal/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-minimal/README.md b/react-minimal/README.md new file mode 100644 index 0000000000..89a82436a7 --- /dev/null +++ b/react-minimal/README.md @@ -0,0 +1,15 @@ +# react-minimal + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-minimal) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-minimal) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-minimal react-minimal +cd react-minimal +npm install +npm run dev +``` diff --git a/react-minimal/index.html b/react-minimal/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-minimal/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-minimal/package.json b/react-minimal/package.json new file mode 100644 index 0000000000..d4c12787fc --- /dev/null +++ b/react-minimal/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-minimal/src/App.tsx b/react-minimal/src/App.tsx new file mode 100644 index 0000000000..523aea224a --- /dev/null +++ b/react-minimal/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/minimal' + +export default function App() { + return +} diff --git a/react-minimal/src/app.css b/react-minimal/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-minimal/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-minimal/src/components/editor/examples/minimal/editor.tsx b/react-minimal/src/components/editor/examples/minimal/editor.tsx new file mode 100644 index 0000000000..fd22ae2a62 --- /dev/null +++ b/react-minimal/src/components/editor/examples/minimal/editor.tsx @@ -0,0 +1,22 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+ ) +} diff --git a/react-minimal/src/components/editor/examples/minimal/index.ts b/react-minimal/src/components/editor/examples/minimal/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-minimal/src/components/editor/examples/minimal/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-minimal/src/main.tsx b/react-minimal/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-minimal/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-minimal/tsconfig.app.json b/react-minimal/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-minimal/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-minimal/tsconfig.json b/react-minimal/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-minimal/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-minimal/tsconfig.node.json b/react-minimal/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-minimal/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-minimal/vite.config.ts b/react-minimal/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-minimal/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-page/.gitignore b/react-page/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-page/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-page/README.md b/react-page/README.md new file mode 100644 index 0000000000..b384224910 --- /dev/null +++ b/react-page/README.md @@ -0,0 +1,15 @@ +# react-page + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-page) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-page) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-page react-page +cd react-page +npm install +npm run dev +``` diff --git a/react-page/index.html b/react-page/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-page/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-page/package.json b/react-page/package.json new file mode 100644 index 0000000000..a4c2e39ecf --- /dev/null +++ b/react-page/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-page", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-page/src/App.tsx b/react-page/src/App.tsx new file mode 100644 index 0000000000..b55eaee6c8 --- /dev/null +++ b/react-page/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/page' + +export default function App() { + return +} diff --git a/react-page/src/app.css b/react-page/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-page/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-page/src/components/editor/examples/page/editor.tsx b/react-page/src/components/editor/examples/page/editor.tsx new file mode 100644 index 0000000000..13dbbec432 --- /dev/null +++ b/react-page/src/components/editor/examples/page/editor.tsx @@ -0,0 +1,49 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/page/style.css' +import './zoom.css' + +import { clsx, createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo, useState } from 'react' + +import { sampleContent } from '../../sample/sample-doc-page' + +import { defineExtension } from './extension' +import PaperController from './paper-controller' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ + extension, + defaultContent, + }) + }, [defaultContent]) + + const [zoom, setZoom] = useState(50) + + return ( + +
+ +
+
+ + ) +} diff --git a/react-page/src/components/editor/examples/page/extension.ts b/react-page/src/components/editor/examples/page/extension.ts new file mode 100644 index 0000000000..edf01e897b --- /dev/null +++ b/react-page/src/components/editor/examples/page/extension.ts @@ -0,0 +1,9 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePageBreak } from 'prosekit/extensions/page' + +export function defineExtension() { + return union(defineBasicExtension(), definePageBreak()) +} + +export type EditorExtension = ReturnType diff --git a/react-page/src/components/editor/examples/page/index.ts b/react-page/src/components/editor/examples/page/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-page/src/components/editor/examples/page/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-page/src/components/editor/examples/page/paper-controller.tsx b/react-page/src/components/editor/examples/page/paper-controller.tsx new file mode 100644 index 0000000000..f79ac700b4 --- /dev/null +++ b/react-page/src/components/editor/examples/page/paper-controller.tsx @@ -0,0 +1,142 @@ +'use client' + +import { + definePageRendering, + type PageRenderingOptions, +} from 'prosekit/extensions/page' +import { useExtension } from 'prosekit/react' +import { useEffect, useId, useMemo, useState } from 'react' + +// Paper sizes in pixels at 96 DPI +const PAPER_SIZES = { + A3: { short: 1123, long: 1587 }, + A4: { short: 794, long: 1123 }, + A5: { short: 559, long: 794 }, + B4: { short: 945, long: 1334 }, + B5: { short: 665, long: 945 }, + letter: { short: 816, long: 1056 }, +} as const + +type PaperSize = keyof typeof PAPER_SIZES +type Orientation = 'portrait' | 'landscape' + +export default function PaperController({ + zoom, + setZoom, +}: { + zoom: number + setZoom: (zoom: number) => void +}) { + const id = useId() + const [paperSize, setPaperSize] = useState('A4') + const [orientation, setOrientation] = useState('portrait') + const [margin, setMargin] = useState(70) + const [enablePageLayout, setEnablePageLayout] = useState(true) + + const pageRenderingOptions: PageRenderingOptions = useMemo(() => { + const { short, long } = PAPER_SIZES[paperSize] + const pageWidth = orientation === 'portrait' ? short : long + const pageHeight = orientation === 'portrait' ? long : short + + return { + pageWidth, + pageHeight, + marginTop: margin, + marginRight: margin, + marginBottom: margin, + marginLeft: margin, + } + }, [paperSize, orientation, margin]) + + useEffect(() => { + const styleId = 'print-page-style' + let style = document.getElementById(styleId) as HTMLStyleElement | null + if (!style) { + style = document.createElement('style') + style.id = styleId + document.head.appendChild(style) + } + style.textContent = `@page { size: ${paperSize} ${orientation}; margin: 0; }` + + return () => { + style.textContent = '' + } + }, [paperSize, orientation]) + + const extension = useMemo(() => { + return enablePageLayout ? definePageRendering(pageRenderingOptions) : null + }, [pageRenderingOptions, enablePageLayout]) + + useExtension(extension) + + return ( +
+ + + + + + + + + + +
+ ) +} diff --git a/react-page/src/components/editor/examples/page/zoom.css b/react-page/src/components/editor/examples/page/zoom.css new file mode 100644 index 0000000000..bd81302639 --- /dev/null +++ b/react-page/src/components/editor/examples/page/zoom.css @@ -0,0 +1,9 @@ +div[data-editor-zoom] { + zoom: var(--zoom); +} + +@media print { + div[data-editor-zoom] { + zoom: 1; + } +} diff --git a/react-page/src/components/editor/sample/sample-doc-page.ts b/react-page/src/components/editor/sample/sample-doc-page.ts new file mode 100644 index 0000000000..60e78ac18e --- /dev/null +++ b/react-page/src/components/editor/sample/sample-doc-page.ts @@ -0,0 +1,98 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Page Layout Demo' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is the first page.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The content below will be on a new page because of a page break. You can insert a page break by pressing Command+Enter on Mac or Ctrl+Enter on Windows and Linux.', + }, + ], + }, + { type: 'pageBreak' }, + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Page 2' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is the second page.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'When the content on a page exceeds the available height, it will automatically flow to the next page. This is similar to how traditional word processors like Microsoft Word handle pagination.', + }, + ], + }, + { type: 'image', attrs: { src: 'https://placehold.co/600x500' } }, + { type: 'image', attrs: { src: 'https://placehold.co/600x500' } }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The images above exceed the available height on the second page, so they automatically flow to the next page.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Known Limitation' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Page breaks only occur between block elements. A single block taller than the remaining space on the page will overflow to the next page rather than split. In other words, you cannot split a node like paragraph or a table across pages. The paragraph below demonstrates this.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'This is a very long paragraph that demonstrates the limitation of block-level pagination.', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [{ type: 'italic' }], + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.', + }, + ], + }, + ], +} diff --git a/react-page/src/main.tsx b/react-page/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-page/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-page/tsconfig.app.json b/react-page/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-page/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-page/tsconfig.json b/react-page/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-page/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-page/tsconfig.node.json b/react-page/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-page/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-page/vite.config.ts b/react-page/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-page/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-placeholder/.gitignore b/react-placeholder/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-placeholder/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-placeholder/README.md b/react-placeholder/README.md new file mode 100644 index 0000000000..27cbbdd306 --- /dev/null +++ b/react-placeholder/README.md @@ -0,0 +1,15 @@ +# react-placeholder + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-placeholder) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-placeholder) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-placeholder react-placeholder +cd react-placeholder +npm install +npm run dev +``` diff --git a/react-placeholder/index.html b/react-placeholder/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-placeholder/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-placeholder/package.json b/react-placeholder/package.json new file mode 100644 index 0000000000..3ee8b24119 --- /dev/null +++ b/react-placeholder/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-placeholder", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-placeholder/src/App.tsx b/react-placeholder/src/App.tsx new file mode 100644 index 0000000000..919da8503a --- /dev/null +++ b/react-placeholder/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/placeholder' + +export default function App() { + return +} diff --git a/react-placeholder/src/app.css b/react-placeholder/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-placeholder/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-placeholder/src/components/editor/examples/placeholder/editor.tsx b/react-placeholder/src/components/editor/examples/placeholder/editor.tsx new file mode 100644 index 0000000000..1ff28c3752 --- /dev/null +++ b/react-placeholder/src/components/editor/examples/placeholder/editor.tsx @@ -0,0 +1,41 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, jsonFromNode, type NodeJSON } from 'prosekit/core' +import type { ProseMirrorNode } from 'prosekit/pm/model' +import { ProseKit, useDocChange } from 'prosekit/react' +import { useCallback, useMemo } from 'react' + +import { defineExtension } from './extension' + +export default function Editor(props: { + initialContent?: NodeJSON + onDocUpdate?: (doc: NodeJSON) => void +}) { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent: props.initialContent }) + }, [props.initialContent]) + + const { onDocUpdate } = props + const handleDocChange = useCallback( + (doc: ProseMirrorNode) => onDocUpdate?.(jsonFromNode(doc)), + [onDocUpdate], + ) + useDocChange(handleDocChange, { editor }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/react-placeholder/src/components/editor/examples/placeholder/extension.ts b/react-placeholder/src/components/editor/examples/placeholder/extension.ts new file mode 100644 index 0000000000..12d0ba26f4 --- /dev/null +++ b/react-placeholder/src/components/editor/examples/placeholder/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Type something...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-placeholder/src/components/editor/examples/placeholder/index.ts b/react-placeholder/src/components/editor/examples/placeholder/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-placeholder/src/components/editor/examples/placeholder/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-placeholder/src/main.tsx b/react-placeholder/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-placeholder/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-placeholder/tsconfig.app.json b/react-placeholder/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-placeholder/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-placeholder/tsconfig.json b/react-placeholder/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-placeholder/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-placeholder/tsconfig.node.json b/react-placeholder/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-placeholder/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-placeholder/vite.config.ts b/react-placeholder/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-placeholder/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-readonly/.gitignore b/react-readonly/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-readonly/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-readonly/README.md b/react-readonly/README.md new file mode 100644 index 0000000000..272e1ce1bc --- /dev/null +++ b/react-readonly/README.md @@ -0,0 +1,15 @@ +# react-readonly + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-readonly) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-readonly) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-readonly react-readonly +cd react-readonly +npm install +npm run dev +``` diff --git a/react-readonly/index.html b/react-readonly/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-readonly/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-readonly/package.json b/react-readonly/package.json new file mode 100644 index 0000000000..d615980017 --- /dev/null +++ b/react-readonly/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-readonly", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-readonly/src/App.tsx b/react-readonly/src/App.tsx new file mode 100644 index 0000000000..dc728e840f --- /dev/null +++ b/react-readonly/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/readonly' + +export default function App() { + return +} diff --git a/react-readonly/src/app.css b/react-readonly/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-readonly/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-readonly/src/components/editor/examples/readonly/editor.tsx b/react-readonly/src/components/editor/examples/readonly/editor.tsx new file mode 100644 index 0000000000..195084fd14 --- /dev/null +++ b/react-readonly/src/components/editor/examples/readonly/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-readonly' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-readonly/src/components/editor/examples/readonly/extension.ts b/react-readonly/src/components/editor/examples/readonly/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/react-readonly/src/components/editor/examples/readonly/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/react-readonly/src/components/editor/examples/readonly/index.ts b/react-readonly/src/components/editor/examples/readonly/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-readonly/src/components/editor/examples/readonly/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-readonly/src/components/editor/examples/readonly/toolbar.tsx b/react-readonly/src/components/editor/examples/readonly/toolbar.tsx new file mode 100644 index 0000000000..4321339858 --- /dev/null +++ b/react-readonly/src/components/editor/examples/readonly/toolbar.tsx @@ -0,0 +1,21 @@ +'use client' + +import { Button } from '../../ui/button' + +import { useReadonly } from './use-readonly' + +export default function Toolbar() { + const { readonly, setReadonly } = useReadonly() + + return ( +
+ + + +
+ ) +} diff --git a/react-readonly/src/components/editor/examples/readonly/use-readonly.ts b/react-readonly/src/components/editor/examples/readonly/use-readonly.ts new file mode 100644 index 0000000000..90699e2168 --- /dev/null +++ b/react-readonly/src/components/editor/examples/readonly/use-readonly.ts @@ -0,0 +1,14 @@ +import { defineReadonly } from 'prosekit/extensions/readonly' +import { useExtension } from 'prosekit/react' +import { useMemo, useState } from 'react' + +export function useReadonly() { + const [readonly, setReadonly] = useState(true) + + const extension = useMemo(() => { + return readonly ? defineReadonly() : null + }, [readonly]) + useExtension(extension) + + return { readonly, setReadonly } +} diff --git a/react-readonly/src/components/editor/sample/sample-doc-readonly.ts b/react-readonly/src/components/editor/sample/sample-doc-readonly.ts new file mode 100644 index 0000000000..abd9e2c6ac --- /dev/null +++ b/react-readonly/src/components/editor/sample/sample-doc-readonly.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', + }, + ], + }, + ], +} diff --git a/react-readonly/src/components/editor/ui/button/button.tsx b/react-readonly/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-readonly/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-readonly/src/components/editor/ui/button/index.ts b/react-readonly/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-readonly/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-readonly/src/main.tsx b/react-readonly/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-readonly/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-readonly/tsconfig.app.json b/react-readonly/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-readonly/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-readonly/tsconfig.json b/react-readonly/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-readonly/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-readonly/tsconfig.node.json b/react-readonly/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-readonly/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-readonly/vite.config.ts b/react-readonly/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-readonly/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-rtl/.gitignore b/react-rtl/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-rtl/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-rtl/README.md b/react-rtl/README.md new file mode 100644 index 0000000000..40016e9cca --- /dev/null +++ b/react-rtl/README.md @@ -0,0 +1,15 @@ +# react-rtl + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-rtl) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-rtl) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-rtl react-rtl +cd react-rtl +npm install +npm run dev +``` diff --git a/react-rtl/index.html b/react-rtl/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-rtl/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-rtl/package.json b/react-rtl/package.json new file mode 100644 index 0000000000..a5d2861c4c --- /dev/null +++ b/react-rtl/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-rtl", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-rtl/src/App.tsx b/react-rtl/src/App.tsx new file mode 100644 index 0000000000..b7c8653ece --- /dev/null +++ b/react-rtl/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/rtl' + +export default function App() { + return +} diff --git a/react-rtl/src/app.css b/react-rtl/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-rtl/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-rtl/src/components/editor/examples/rtl/editor.tsx b/react-rtl/src/components/editor/examples/rtl/editor.tsx new file mode 100644 index 0000000000..186955c590 --- /dev/null +++ b/react-rtl/src/components/editor/examples/rtl/editor.tsx @@ -0,0 +1,52 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-rtl' +import { sampleUploader } from '../../sample/sample-uploader' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' +import { InlineMenu } from '../../ui/inline-menu' +import { SlashMenu } from '../../ui/slash-menu' +import { TableHandle } from '../../ui/table-handle' +import { Toolbar } from '../../ui/toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+ + + + + +
+
+
+ ) +} diff --git a/react-rtl/src/components/editor/examples/rtl/index.ts b/react-rtl/src/components/editor/examples/rtl/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-rtl/src/components/editor/examples/rtl/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-rtl/src/components/editor/sample/sample-doc-rtl.ts b/react-rtl/src/components/editor/sample/sample-doc-rtl.ts new file mode 100644 index 0000000000..696e797724 --- /dev/null +++ b/react-rtl/src/components/editor/sample/sample-doc-rtl.ts @@ -0,0 +1,187 @@ +import type { NodeJSON } from 'prosekit/core' + +const translation = { + Paragraph: 'فقرة', + 'Root list item': 'عنصر قائمة جذري', + 'Sub list item': 'عنصر قائمة فرعي', + 'Completed task': 'مهمة مكتملة', + 'Pending task': 'مهمة قيد الانتظار', + Quote: 'اقتباس', +} as const + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Right to Left' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Paragraph'] }], + }, + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Root list item'] }], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Completed task'] }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Pending task'] }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: 'hello world', + }, + ], + }, + + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, + ], + }, + ], + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: translation['Quote'], + }, + ], + }, + ], + }, + ], +} diff --git a/react-rtl/src/components/editor/sample/sample-uploader.ts b/react-rtl/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/react-rtl/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/react-rtl/src/components/editor/ui/block-handle/block-handle.tsx b/react-rtl/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..3cc6028d5c --- /dev/null +++ b/react-rtl/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,33 @@ +'use client' + +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/react/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/react-rtl/src/components/editor/ui/block-handle/index.ts b/react-rtl/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/react-rtl/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/react-rtl/src/components/editor/ui/button/button.tsx b/react-rtl/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-rtl/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-rtl/src/components/editor/ui/button/index.ts b/react-rtl/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-rtl/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/react-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx new file mode 100644 index 0000000000..87c1746622 --- /dev/null +++ b/react-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx @@ -0,0 +1,7 @@ +'use client' + +import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator' + +export default function DropIndicator() { + return +} diff --git a/react-rtl/src/components/editor/ui/drop-indicator/index.ts b/react-rtl/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..f8fb7139c4 --- /dev/null +++ b/react-rtl/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator' diff --git a/react-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-rtl/src/components/editor/ui/image-upload-popover/index.ts b/react-rtl/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-rtl/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-rtl/src/components/editor/ui/inline-menu/index.ts b/react-rtl/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/react-rtl/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/react-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..af1b2bb2b7 --- /dev/null +++ b/react-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/react' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/react/inline-popover' +import { useState } from 'react' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/react-rtl/src/components/editor/ui/slash-menu/index.ts b/react-rtl/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/react-rtl/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/react-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/react-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..d0dca0934a --- /dev/null +++ b/react-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,11 @@ +'use client' + +import { AutocompleteEmpty } from 'prosekit/react/autocomplete' + +export default function SlashMenuEmpty() { + return ( + + No results + + ) +} diff --git a/react-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/react-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..349c6e8924 --- /dev/null +++ b/react-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,23 @@ +'use client' + +import { AutocompleteItem } from 'prosekit/react/autocomplete' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}) { + return ( + + {props.label} + {props.kbd && ( + + {props.kbd} + + )} + + ) +} diff --git a/react-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx b/react-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..3738f51aab --- /dev/null +++ b/react-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,102 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/react' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor.commands.setParagraph()} + /> + + editor.commands.setHeading({ level: 1 })} + /> + + editor.commands.setHeading({ level: 2 })} + /> + + editor.commands.setHeading({ level: 3 })} + /> + + editor.commands.wrapInList({ kind: 'bullet' })} + /> + + editor.commands.wrapInList({ kind: 'ordered' })} + /> + + editor.commands.wrapInList({ kind: 'task' })} + /> + + editor.commands.wrapInList({ kind: 'toggle' })} + /> + + editor.commands.setBlockquote()} + /> + + editor.commands.insertTable({ row: 3, col: 3 })} + /> + + editor.commands.insertHorizontalRule()} + /> + + editor.commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/react-rtl/src/components/editor/ui/table-handle/index.ts b/react-rtl/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/react-rtl/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/react-rtl/src/components/editor/ui/table-handle/table-handle.tsx b/react-rtl/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..b90b351382 --- /dev/null +++ b/react-rtl/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,188 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/react' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/react/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/react/table-handle' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props) { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + {state.addTableColumnBefore.canExec && ( + + Insert Left + + )} + {state.addTableColumnAfter.canExec && ( + + Insert Right + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableColumn.canExec && ( + + Delete Column + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+ + + + +
+
+ + + {state.addTableRowAbove.canExec && ( + + Insert Above + + )} + {state.addTableRowBelow.canExec && ( + + Insert Below + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableRow.canExec && ( + + Delete Row + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+
+ ) +} diff --git a/react-rtl/src/components/editor/ui/toolbar/index.ts b/react-rtl/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-rtl/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-rtl/src/components/editor/ui/toolbar/toolbar.tsx b/react-rtl/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-rtl/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-rtl/src/main.tsx b/react-rtl/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-rtl/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-rtl/tsconfig.app.json b/react-rtl/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-rtl/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-rtl/tsconfig.json b/react-rtl/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-rtl/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-rtl/tsconfig.node.json b/react-rtl/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-rtl/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-rtl/vite.config.ts b/react-rtl/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-rtl/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-save-html/.gitignore b/react-save-html/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-save-html/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-save-html/README.md b/react-save-html/README.md new file mode 100644 index 0000000000..4be15ecaff --- /dev/null +++ b/react-save-html/README.md @@ -0,0 +1,15 @@ +# react-save-html + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-save-html) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-save-html) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-save-html react-save-html +cd react-save-html +npm install +npm run dev +``` diff --git a/react-save-html/index.html b/react-save-html/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-save-html/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-save-html/package.json b/react-save-html/package.json new file mode 100644 index 0000000000..91bd766538 --- /dev/null +++ b/react-save-html/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-save-html", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-save-html/src/App.tsx b/react-save-html/src/App.tsx new file mode 100644 index 0000000000..cd1a678bb6 --- /dev/null +++ b/react-save-html/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-html' + +export default function App() { + return +} diff --git a/react-save-html/src/app.css b/react-save-html/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-save-html/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-save-html/src/components/editor/examples/save-html/editor.tsx b/react-save-html/src/components/editor/examples/save-html/editor.tsx new file mode 100644 index 0000000000..0b0dd123d5 --- /dev/null +++ b/react-save-html/src/components/editor/examples/save-html/editor.tsx @@ -0,0 +1,76 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, jsonFromHTML } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/react' +import { useCallback, useMemo, useState } from 'react' + +export default function Editor() { + // A list of saved documents, stored as HTML strings + const [records, setRecords] = useState([]) + // Whether there are unsaved changes + const [hasUnsavedChange, setHasUnsavedChange] = useState(false) + // A key to force a re-render of the editor + const [key, setKey] = useState(1) + + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension }) + }, []) + + const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) + useDocChange(handleDocChange, { editor }) + + const handleSave = useCallback(() => { + const record = editor.getDocHTML() + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + }, [editor]) + + const handleLoad = useCallback( + (record: string) => { + editor.setContent(jsonFromHTML(record, { schema: editor.schema })) + setHasUnsavedChange(false) + setKey((prev) => prev + 1) + }, + [editor], + ) + + return ( +
+ +
    + {records.map((record, index) => ( +
  • + + +
    {record}
    +
    +
  • + ))} +
+ +
+
+
+
+
+ ) +} diff --git a/react-save-html/src/components/editor/examples/save-html/index.ts b/react-save-html/src/components/editor/examples/save-html/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-save-html/src/components/editor/examples/save-html/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-save-html/src/main.tsx b/react-save-html/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-save-html/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-save-html/tsconfig.app.json b/react-save-html/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-save-html/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-save-html/tsconfig.json b/react-save-html/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-save-html/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-save-html/tsconfig.node.json b/react-save-html/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-save-html/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-save-html/vite.config.ts b/react-save-html/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-save-html/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-save-json/.gitignore b/react-save-json/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-save-json/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-save-json/README.md b/react-save-json/README.md new file mode 100644 index 0000000000..6f336a1553 --- /dev/null +++ b/react-save-json/README.md @@ -0,0 +1,15 @@ +# react-save-json + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-save-json) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-save-json) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-save-json react-save-json +cd react-save-json +npm install +npm run dev +``` diff --git a/react-save-json/index.html b/react-save-json/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-save-json/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-save-json/package.json b/react-save-json/package.json new file mode 100644 index 0000000000..2516e6babf --- /dev/null +++ b/react-save-json/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-save-json", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-save-json/src/App.tsx b/react-save-json/src/App.tsx new file mode 100644 index 0000000000..c35583f0b4 --- /dev/null +++ b/react-save-json/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-json' + +export default function App() { + return +} diff --git a/react-save-json/src/app.css b/react-save-json/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-save-json/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-save-json/src/components/editor/examples/save-json/editor.tsx b/react-save-json/src/components/editor/examples/save-json/editor.tsx new file mode 100644 index 0000000000..74c44bbb98 --- /dev/null +++ b/react-save-json/src/components/editor/examples/save-json/editor.tsx @@ -0,0 +1,76 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/react' +import { useCallback, useMemo, useState } from 'react' + +export default function Editor() { + // A list of saved documents, stored as JSON strings + const [records, setRecords] = useState([]) + // Whether there are unsaved changes + const [hasUnsavedChange, setHasUnsavedChange] = useState(false) + // A key to force a re-render of the editor + const [key, setKey] = useState(1) + + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension }) + }, []) + + const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) + useDocChange(handleDocChange, { editor }) + + const handleSave = useCallback(() => { + const record = JSON.stringify(editor.getDocJSON()) + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + }, [editor]) + + const handleLoad = useCallback( + (record: string) => { + editor.setContent(JSON.parse(record) as NodeJSON) + setHasUnsavedChange(false) + setKey((prev) => prev + 1) + }, + [editor], + ) + + return ( +
+ +
    + {records.map((record, index) => ( +
  • + + +
    {record}
    +
    +
  • + ))} +
+ +
+
+
+
+
+ ) +} diff --git a/react-save-json/src/components/editor/examples/save-json/index.ts b/react-save-json/src/components/editor/examples/save-json/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-save-json/src/components/editor/examples/save-json/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-save-json/src/main.tsx b/react-save-json/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-save-json/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-save-json/tsconfig.app.json b/react-save-json/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-save-json/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-save-json/tsconfig.json b/react-save-json/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-save-json/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-save-json/tsconfig.node.json b/react-save-json/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-save-json/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-save-json/vite.config.ts b/react-save-json/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-save-json/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-save-markdown/.gitignore b/react-save-markdown/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-save-markdown/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-save-markdown/README.md b/react-save-markdown/README.md new file mode 100644 index 0000000000..4964905102 --- /dev/null +++ b/react-save-markdown/README.md @@ -0,0 +1,15 @@ +# react-save-markdown + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-save-markdown) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-save-markdown) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-save-markdown react-save-markdown +cd react-save-markdown +npm install +npm run dev +``` diff --git a/react-save-markdown/index.html b/react-save-markdown/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-save-markdown/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-save-markdown/package.json b/react-save-markdown/package.json new file mode 100644 index 0000000000..5749c9e7ad --- /dev/null +++ b/react-save-markdown/package.json @@ -0,0 +1,35 @@ +{ + "name": "example-react-save-markdown", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "rehype-parse": "^9.0.1", + "rehype-remark": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-html": "^16.0.1", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.5" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-save-markdown/src/App.tsx b/react-save-markdown/src/App.tsx new file mode 100644 index 0000000000..776d1fdf5b --- /dev/null +++ b/react-save-markdown/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-markdown' + +export default function App() { + return +} diff --git a/react-save-markdown/src/app.css b/react-save-markdown/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-save-markdown/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-save-markdown/src/components/editor/examples/save-markdown/editor.tsx b/react-save-markdown/src/components/editor/examples/save-markdown/editor.tsx new file mode 100644 index 0000000000..bcfe0d9724 --- /dev/null +++ b/react-save-markdown/src/components/editor/examples/save-markdown/editor.tsx @@ -0,0 +1,80 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, jsonFromHTML } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/react' +import { useCallback, useMemo, useState } from 'react' + +import { htmlFromMarkdown, markdownFromHTML } from './markdown' + +export default function Editor() { + // A list of saved documents, stored as Markdown strings + const [records, setRecords] = useState([]) + // Whether there are unsaved changes + const [hasUnsavedChange, setHasUnsavedChange] = useState(false) + // A key to force a re-render of the editor + const [key, setKey] = useState(1) + + const editor = useMemo(() => { + const extension = defineBasicExtension() + return createEditor({ extension }) + }, []) + + const handleDocChange = useCallback(() => setHasUnsavedChange(true), []) + useDocChange(handleDocChange, { editor }) + + const handleSave = useCallback(() => { + const html = editor.getDocHTML() + const record = markdownFromHTML(html) + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + }, [editor]) + + const handleLoad = useCallback( + (record: string) => { + const html = htmlFromMarkdown(record) + editor.setContent(jsonFromHTML(html, { schema: editor.schema })) + setHasUnsavedChange(false) + setKey((prev) => prev + 1) + }, + [editor], + ) + + return ( +
+ +
    + {records.map((record, index) => ( +
  • + + +
    {record}
    +
    +
  • + ))} +
+ +
+
+
+
+
+ ) +} diff --git a/react-save-markdown/src/components/editor/examples/save-markdown/index.ts b/react-save-markdown/src/components/editor/examples/save-markdown/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-save-markdown/src/components/editor/examples/save-markdown/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/react-save-markdown/src/components/editor/examples/save-markdown/markdown.ts new file mode 100644 index 0000000000..3f930adad2 --- /dev/null +++ b/react-save-markdown/src/components/editor/examples/save-markdown/markdown.ts @@ -0,0 +1,26 @@ +import rehypeParse from 'rehype-parse' +import rehypeRemark from 'rehype-remark' +import remarkGfm from 'remark-gfm' +import remarkHtml from 'remark-html' +import remarkParse from 'remark-parse' +import remarkStringify from 'remark-stringify' +import { unified } from 'unified' + +export function markdownFromHTML(html: string): string { + return unified() + .use(rehypeParse) + .use(rehypeRemark) + .use(remarkGfm) + .use(remarkStringify) + .processSync(html) + .toString() +} + +export function htmlFromMarkdown(markdown: string): string { + return unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkHtml) + .processSync(markdown) + .toString() +} diff --git a/react-save-markdown/src/main.tsx b/react-save-markdown/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-save-markdown/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-save-markdown/tsconfig.app.json b/react-save-markdown/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-save-markdown/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-save-markdown/tsconfig.json b/react-save-markdown/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-save-markdown/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-save-markdown/tsconfig.node.json b/react-save-markdown/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-save-markdown/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-save-markdown/vite.config.ts b/react-save-markdown/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-save-markdown/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-search/.gitignore b/react-search/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-search/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-search/README.md b/react-search/README.md new file mode 100644 index 0000000000..48cd70bb95 --- /dev/null +++ b/react-search/README.md @@ -0,0 +1,15 @@ +# react-search + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-search) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-search) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-search react-search +cd react-search +npm install +npm run dev +``` diff --git a/react-search/index.html b/react-search/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-search/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-search/package.json b/react-search/package.json new file mode 100644 index 0000000000..b61ebebc32 --- /dev/null +++ b/react-search/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-search", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-search/src/App.tsx b/react-search/src/App.tsx new file mode 100644 index 0000000000..2f6b77056f --- /dev/null +++ b/react-search/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/search' + +export default function App() { + return +} diff --git a/react-search/src/app.css b/react-search/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-search/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-search/src/components/editor/examples/search/editor.tsx b/react-search/src/components/editor/examples/search/editor.tsx new file mode 100644 index 0000000000..6f5d80b394 --- /dev/null +++ b/react-search/src/components/editor/examples/search/editor.tsx @@ -0,0 +1,43 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/search/style.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-search' +import { Search } from '../../ui/search' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ + extension, + defaultContent, + }) + }, [defaultContent]) + + return ( + +
+
+ +
+
+
+
+ ) +} diff --git a/react-search/src/components/editor/examples/search/extension.ts b/react-search/src/components/editor/examples/search/extension.ts new file mode 100644 index 0000000000..10ff13f614 --- /dev/null +++ b/react-search/src/components/editor/examples/search/extension.ts @@ -0,0 +1,9 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineSearchCommands } from 'prosekit/extensions/search' + +export function defineExtension() { + return union(defineBasicExtension(), defineSearchCommands()) +} + +export type EditorExtension = ReturnType diff --git a/react-search/src/components/editor/examples/search/index.ts b/react-search/src/components/editor/examples/search/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-search/src/components/editor/examples/search/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-search/src/components/editor/sample/sample-doc-search.ts b/react-search/src/components/editor/sample/sample-doc-search.ts new file mode 100644 index 0000000000..c8160cca2a --- /dev/null +++ b/react-search/src/components/editor/sample/sample-doc-search.ts @@ -0,0 +1,79 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Baa, baa, black sheep,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Have you any wool?', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Yes, sir, yes, sir,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Three bags full;', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'One for the master,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the dame,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the little boy', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Who lives down the lane.', + }, + ], + }, + ], +} diff --git a/react-search/src/components/editor/ui/button/button.tsx b/react-search/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-search/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-search/src/components/editor/ui/button/index.ts b/react-search/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-search/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-search/src/components/editor/ui/search/index.ts b/react-search/src/components/editor/ui/search/index.ts new file mode 100644 index 0000000000..0a1f03c720 --- /dev/null +++ b/react-search/src/components/editor/ui/search/index.ts @@ -0,0 +1 @@ +export { default as Search } from './search' diff --git a/react-search/src/components/editor/ui/search/search.tsx b/react-search/src/components/editor/ui/search/search.tsx new file mode 100644 index 0000000000..2ab70ee512 --- /dev/null +++ b/react-search/src/components/editor/ui/search/search.tsx @@ -0,0 +1,169 @@ +'use client' + +import { + defineSearchQuery, + type SearchCommandsExtension, +} from 'prosekit/extensions/search' +import { useEditor, useExtension } from 'prosekit/react' +import { useMemo, useState } from 'react' + +import { Button } from '../button' + +export default function Search(props: { onClose?: VoidFunction }) { + const [showReplace, setShowReplace] = useState(false) + const toggleReplace = () => setShowReplace((value) => !value) + + const [searchText, setSearchText] = useState('') + const [replaceText, setReplaceText] = useState('') + const [caseSensitive, setCaseSensitive] = useState(false) + const [wholeWord, setWholeWord] = useState(false) + const [regexp, setRegexp] = useState(false) + const [literal, setLiteral] = useState(false) + + const extension = useMemo(() => { + if (!searchText) { + return null + } + return defineSearchQuery({ + search: searchText, + replace: replaceText, + caseSensitive, + wholeWord, + regexp, + literal, + }) + }, [searchText, replaceText, caseSensitive, wholeWord, regexp, literal]) + + useExtension(extension) + + const editor = useEditor() + + const handleSearchKeyDown = (event: React.KeyboardEvent) => { + if (isEnter(event)) { + event.preventDefault() + editor.commands.findNext() + } else if (isShiftEnter(event)) { + event.preventDefault() + editor.commands.findPrev() + } + } + + const handleReplaceKeyDown = (event: React.KeyboardEvent) => { + if (isEnter(event)) { + event.preventDefault() + editor.commands.replaceNext() + } else if (isShiftEnter(event)) { + event.preventDefault() + editor.commands.replaceAll() + } + } + + return ( +
+ + setSearchText(event.target.value)} + onKeyDown={handleSearchKeyDown} + className="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" + /> +
+ + + + + + + +
+ {showReplace && ( + setReplaceText(event.target.value)} + onKeyDown={handleReplaceKeyDown} + className="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" + /> + )} + {showReplace && ( +
+ + +
+ )} +
+ ) +} + +function isEnter(event: React.KeyboardEvent) { + return ( + event.key === 'Enter' && + !event.shiftKey && + !event.metaKey && + !event.altKey && + !event.ctrlKey && + !event.nativeEvent.isComposing + ) +} + +function isShiftEnter(event: React.KeyboardEvent) { + return ( + event.key === 'Enter' && + event.shiftKey && + !event.metaKey && + !event.altKey && + !event.ctrlKey && + !event.nativeEvent.isComposing + ) +} diff --git a/react-search/src/main.tsx b/react-search/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-search/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-search/tsconfig.app.json b/react-search/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-search/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-search/tsconfig.json b/react-search/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-search/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-search/tsconfig.node.json b/react-search/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-search/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-search/vite.config.ts b/react-search/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-search/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-slash-menu/.gitignore b/react-slash-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-slash-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-slash-menu/README.md b/react-slash-menu/README.md new file mode 100644 index 0000000000..83a24da4b0 --- /dev/null +++ b/react-slash-menu/README.md @@ -0,0 +1,15 @@ +# react-slash-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-slash-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-slash-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-slash-menu react-slash-menu +cd react-slash-menu +npm install +npm run dev +``` diff --git a/react-slash-menu/index.html b/react-slash-menu/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-slash-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-slash-menu/package.json b/react-slash-menu/package.json new file mode 100644 index 0000000000..7e4b496ddf --- /dev/null +++ b/react-slash-menu/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-slash-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-slash-menu/src/App.tsx b/react-slash-menu/src/App.tsx new file mode 100644 index 0000000000..cf430661be --- /dev/null +++ b/react-slash-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/slash-menu' + +export default function App() { + return +} diff --git a/react-slash-menu/src/app.css b/react-slash-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-slash-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-slash-menu/src/components/editor/examples/slash-menu/editor.tsx b/react-slash-menu/src/components/editor/examples/slash-menu/editor.tsx new file mode 100644 index 0000000000..b89d418a89 --- /dev/null +++ b/react-slash-menu/src/components/editor/examples/slash-menu/editor.tsx @@ -0,0 +1,33 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { SlashMenu } from '../../ui/slash-menu' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/react-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/react-slash-menu/src/components/editor/examples/slash-menu/extension.ts new file mode 100644 index 0000000000..0edda60136 --- /dev/null +++ b/react-slash-menu/src/components/editor/examples/slash-menu/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-slash-menu/src/components/editor/examples/slash-menu/index.ts b/react-slash-menu/src/components/editor/examples/slash-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-slash-menu/src/components/editor/examples/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-slash-menu/src/components/editor/ui/slash-menu/index.ts b/react-slash-menu/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/react-slash-menu/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..d0dca0934a --- /dev/null +++ b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,11 @@ +'use client' + +import { AutocompleteEmpty } from 'prosekit/react/autocomplete' + +export default function SlashMenuEmpty() { + return ( + + No results + + ) +} diff --git a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..349c6e8924 --- /dev/null +++ b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,23 @@ +'use client' + +import { AutocompleteItem } from 'prosekit/react/autocomplete' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}) { + return ( + + {props.label} + {props.kbd && ( + + {props.kbd} + + )} + + ) +} diff --git a/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..3738f51aab --- /dev/null +++ b/react-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,102 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/react' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor.commands.setParagraph()} + /> + + editor.commands.setHeading({ level: 1 })} + /> + + editor.commands.setHeading({ level: 2 })} + /> + + editor.commands.setHeading({ level: 3 })} + /> + + editor.commands.wrapInList({ kind: 'bullet' })} + /> + + editor.commands.wrapInList({ kind: 'ordered' })} + /> + + editor.commands.wrapInList({ kind: 'task' })} + /> + + editor.commands.wrapInList({ kind: 'toggle' })} + /> + + editor.commands.setBlockquote()} + /> + + editor.commands.insertTable({ row: 3, col: 3 })} + /> + + editor.commands.insertHorizontalRule()} + /> + + editor.commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/react-slash-menu/src/main.tsx b/react-slash-menu/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-slash-menu/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-slash-menu/tsconfig.app.json b/react-slash-menu/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-slash-menu/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-slash-menu/tsconfig.json b/react-slash-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-slash-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-slash-menu/tsconfig.node.json b/react-slash-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-slash-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-slash-menu/vite.config.ts b/react-slash-menu/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-slash-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-strike/.gitignore b/react-strike/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-strike/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-strike/README.md b/react-strike/README.md new file mode 100644 index 0000000000..ded25bd4bd --- /dev/null +++ b/react-strike/README.md @@ -0,0 +1,15 @@ +# react-strike + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-strike) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-strike) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-strike react-strike +cd react-strike +npm install +npm run dev +``` diff --git a/react-strike/index.html b/react-strike/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-strike/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-strike/package.json b/react-strike/package.json new file mode 100644 index 0000000000..09c9528605 --- /dev/null +++ b/react-strike/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-strike", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-strike/src/App.tsx b/react-strike/src/App.tsx new file mode 100644 index 0000000000..497a57c0d8 --- /dev/null +++ b/react-strike/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/strike' + +export default function App() { + return +} diff --git a/react-strike/src/app.css b/react-strike/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-strike/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-strike/src/components/editor/examples/strike/editor.tsx b/react-strike/src/components/editor/examples/strike/editor.tsx new file mode 100644 index 0000000000..f3378a871d --- /dev/null +++ b/react-strike/src/components/editor/examples/strike/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-strike' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-strike/src/components/editor/examples/strike/extension.ts b/react-strike/src/components/editor/examples/strike/extension.ts new file mode 100644 index 0000000000..c013303ccc --- /dev/null +++ b/react-strike/src/components/editor/examples/strike/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineStrike(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-strike/src/components/editor/examples/strike/index.ts b/react-strike/src/components/editor/examples/strike/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-strike/src/components/editor/examples/strike/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-strike/src/components/editor/examples/strike/toolbar.tsx b/react-strike/src/components/editor/examples/strike/toolbar.tsx new file mode 100644 index 0000000000..67b359dd17 --- /dev/null +++ b/react-strike/src/components/editor/examples/strike/toolbar.tsx @@ -0,0 +1,34 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + strike: { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/react-strike/src/components/editor/sample/sample-doc-strike.ts b/react-strike/src/components/editor/sample/sample-doc-strike.ts new file mode 100644 index 0000000000..2e025e9b02 --- /dev/null +++ b/react-strike/src/components/editor/sample/sample-doc-strike.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'This is strike', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/react-strike/src/components/editor/ui/button/button.tsx b/react-strike/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-strike/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-strike/src/components/editor/ui/button/index.ts b/react-strike/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-strike/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-strike/src/main.tsx b/react-strike/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-strike/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-strike/tsconfig.app.json b/react-strike/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-strike/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-strike/tsconfig.json b/react-strike/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-strike/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-strike/tsconfig.node.json b/react-strike/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-strike/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-strike/vite.config.ts b/react-strike/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-strike/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-sub-sup/.gitignore b/react-sub-sup/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-sub-sup/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-sub-sup/README.md b/react-sub-sup/README.md new file mode 100644 index 0000000000..02b78e8e1e --- /dev/null +++ b/react-sub-sup/README.md @@ -0,0 +1,15 @@ +# react-sub-sup + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-sub-sup) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-sub-sup) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-sub-sup react-sub-sup +cd react-sub-sup +npm install +npm run dev +``` diff --git a/react-sub-sup/index.html b/react-sub-sup/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-sub-sup/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-sub-sup/package.json b/react-sub-sup/package.json new file mode 100644 index 0000000000..04d6014a0a --- /dev/null +++ b/react-sub-sup/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-sub-sup", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-sub-sup/src/App.tsx b/react-sub-sup/src/App.tsx new file mode 100644 index 0000000000..48e43d6423 --- /dev/null +++ b/react-sub-sup/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/sub-sup' + +export default function App() { + return +} diff --git a/react-sub-sup/src/app.css b/react-sub-sup/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-sub-sup/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-sub-sup/src/components/editor/examples/sub-sup/editor.tsx b/react-sub-sup/src/components/editor/examples/sub-sup/editor.tsx new file mode 100644 index 0000000000..43a765e067 --- /dev/null +++ b/react-sub-sup/src/components/editor/examples/sub-sup/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-sub-sup' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/react-sub-sup/src/components/editor/examples/sub-sup/extension.ts new file mode 100644 index 0000000000..bd67245f86 --- /dev/null +++ b/react-sub-sup/src/components/editor/examples/sub-sup/extension.ts @@ -0,0 +1,32 @@ +import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineMarkInputRule } from 'prosekit/extensions/input-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineSubscript } from 'prosekit/extensions/subscript' +import { defineSuperscript } from 'prosekit/extensions/superscript' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineSubscript(), + defineSuperscript(), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ + : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, + type: 'subscript', + }), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ + : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, + type: 'superscript', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-sub-sup/src/components/editor/examples/sub-sup/index.ts b/react-sub-sup/src/components/editor/examples/sub-sup/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-sub-sup/src/components/editor/examples/sub-sup/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx b/react-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx new file mode 100644 index 0000000000..7a22c8d073 --- /dev/null +++ b/react-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx @@ -0,0 +1,46 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + subscript: { + isActive: editor.marks.subscript.isActive(), + canExec: editor.commands.toggleSubscript.canExec(), + command: () => editor.commands.toggleSubscript(), + }, + superscript: { + isActive: editor.marks.superscript.isActive(), + canExec: editor.commands.toggleSuperscript.canExec(), + command: () => editor.commands.toggleSuperscript(), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + +
+ ) +} diff --git a/react-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/react-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts new file mode 100644 index 0000000000..011be750dc --- /dev/null +++ b/react-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts @@ -0,0 +1,42 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'H', + }, + { + type: 'text', + marks: [ + { + type: 'subscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: 'O is water. x', + }, + { + type: 'text', + marks: [ + { + type: 'superscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: ' is a square.', + }, + ], + }, + ], +} diff --git a/react-sub-sup/src/components/editor/ui/button/button.tsx b/react-sub-sup/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-sub-sup/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-sub-sup/src/components/editor/ui/button/index.ts b/react-sub-sup/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-sub-sup/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-sub-sup/src/main.tsx b/react-sub-sup/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-sub-sup/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-sub-sup/tsconfig.app.json b/react-sub-sup/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-sub-sup/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-sub-sup/tsconfig.json b/react-sub-sup/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-sub-sup/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-sub-sup/tsconfig.node.json b/react-sub-sup/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-sub-sup/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-sub-sup/vite.config.ts b/react-sub-sup/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-sub-sup/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-table/.gitignore b/react-table/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-table/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-table/README.md b/react-table/README.md new file mode 100644 index 0000000000..82de244968 --- /dev/null +++ b/react-table/README.md @@ -0,0 +1,15 @@ +# react-table + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-table) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-table) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-table react-table +cd react-table +npm install +npm run dev +``` diff --git a/react-table/index.html b/react-table/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-table/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-table/package.json b/react-table/package.json new file mode 100644 index 0000000000..733c44d828 --- /dev/null +++ b/react-table/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-table", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-table/src/App.tsx b/react-table/src/App.tsx new file mode 100644 index 0000000000..9d9d957adb --- /dev/null +++ b/react-table/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/table' + +export default function App() { + return +} diff --git a/react-table/src/app.css b/react-table/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-table/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-table/src/components/editor/examples/table/editor.tsx b/react-table/src/components/editor/examples/table/editor.tsx new file mode 100644 index 0000000000..fbd68b0859 --- /dev/null +++ b/react-table/src/components/editor/examples/table/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-table' +import { TableHandle } from '../../ui/table-handle' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/react-table/src/components/editor/examples/table/extension.ts b/react-table/src/components/editor/examples/table/extension.ts new file mode 100644 index 0000000000..ee7b142041 --- /dev/null +++ b/react-table/src/components/editor/examples/table/extension.ts @@ -0,0 +1,20 @@ +import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineTable(), + defineHistory(), + defineGapCursor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-table/src/components/editor/examples/table/index.ts b/react-table/src/components/editor/examples/table/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-table/src/components/editor/examples/table/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-table/src/components/editor/sample/sample-doc-table.ts b/react-table/src/components/editor/sample/sample-doc-table.ts new file mode 100644 index 0000000000..c737121672 --- /dev/null +++ b/react-table/src/components/editor/sample/sample-doc-table.ts @@ -0,0 +1,174 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D1', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D2', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], +} diff --git a/react-table/src/components/editor/ui/table-handle/index.ts b/react-table/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/react-table/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/react-table/src/components/editor/ui/table-handle/table-handle.tsx b/react-table/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..b90b351382 --- /dev/null +++ b/react-table/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,188 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/react' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/react/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/react/table-handle' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props) { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + {state.addTableColumnBefore.canExec && ( + + Insert Left + + )} + {state.addTableColumnAfter.canExec && ( + + Insert Right + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableColumn.canExec && ( + + Delete Column + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+ + + + +
+
+ + + {state.addTableRowAbove.canExec && ( + + Insert Above + + )} + {state.addTableRowBelow.canExec && ( + + Insert Below + + )} + {state.deleteCellSelection.canExec && ( + + Clear Contents + + Del + + + )} + {state.deleteTableRow.canExec && ( + + Delete Row + + )} + {state.deleteTable.canExec && ( + + Delete Table + + )} + + +
+
+
+
+ ) +} diff --git a/react-table/src/main.tsx b/react-table/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-table/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-table/tsconfig.app.json b/react-table/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-table/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-table/tsconfig.json b/react-table/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-table/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-table/tsconfig.node.json b/react-table/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-table/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-table/vite.config.ts b/react-table/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-table/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-text-align/.gitignore b/react-text-align/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-text-align/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-text-align/README.md b/react-text-align/README.md new file mode 100644 index 0000000000..73c219cf00 --- /dev/null +++ b/react-text-align/README.md @@ -0,0 +1,15 @@ +# react-text-align + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-text-align) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-text-align) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-text-align react-text-align +cd react-text-align +npm install +npm run dev +``` diff --git a/react-text-align/index.html b/react-text-align/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-text-align/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-text-align/package.json b/react-text-align/package.json new file mode 100644 index 0000000000..a63da1a323 --- /dev/null +++ b/react-text-align/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-text-align", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-text-align/src/App.tsx b/react-text-align/src/App.tsx new file mode 100644 index 0000000000..0c049df602 --- /dev/null +++ b/react-text-align/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/text-align' + +export default function App() { + return +} diff --git a/react-text-align/src/app.css b/react-text-align/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-text-align/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-text-align/src/components/editor/examples/text-align/editor.tsx b/react-text-align/src/components/editor/examples/text-align/editor.tsx new file mode 100644 index 0000000000..bdfbfd031e --- /dev/null +++ b/react-text-align/src/components/editor/examples/text-align/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-text-align' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-text-align/src/components/editor/examples/text-align/extension.ts b/react-text-align/src/components/editor/examples/text-align/extension.ts new file mode 100644 index 0000000000..f1ae44dc7c --- /dev/null +++ b/react-text-align/src/components/editor/examples/text-align/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineTextAlign } from 'prosekit/extensions/text-align' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextAlign({ types: ['paragraph', 'heading'] }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-text-align/src/components/editor/examples/text-align/index.ts b/react-text-align/src/components/editor/examples/text-align/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-text-align/src/components/editor/examples/text-align/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-text-align/src/components/editor/examples/text-align/toolbar.tsx b/react-text-align/src/components/editor/examples/text-align/toolbar.tsx new file mode 100644 index 0000000000..b86702019a --- /dev/null +++ b/react-text-align/src/components/editor/examples/text-align/toolbar.tsx @@ -0,0 +1,80 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function isTextAlignActive(editor: Editor, value: string) { + return Object.values(editor.nodes).some((node) => { + // @ts-expect-error textAlign may not be available on every node + return node.isActive({ textAlign: value }) + }) +} + +function getToolbarItems(editor: Editor) { + return { + left: { + isActive: isTextAlignActive(editor, 'left'), + canExec: editor.commands.setTextAlign.canExec('left'), + command: () => editor.commands.setTextAlign('left'), + }, + center: { + isActive: isTextAlignActive(editor, 'center'), + canExec: editor.commands.setTextAlign.canExec('center'), + command: () => editor.commands.setTextAlign('center'), + }, + right: { + isActive: isTextAlignActive(editor, 'right'), + canExec: editor.commands.setTextAlign.canExec('right'), + command: () => editor.commands.setTextAlign('right'), + }, + justify: { + isActive: isTextAlignActive(editor, 'justify'), + canExec: editor.commands.setTextAlign.canExec('justify'), + command: () => editor.commands.setTextAlign('justify'), + }, + } +} + +export default function Toolbar() { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + + + + + + +
+ ) +} diff --git a/react-text-align/src/components/editor/sample/sample-doc-text-align.ts b/react-text-align/src/components/editor/sample/sample-doc-text-align.ts new file mode 100644 index 0000000000..0724cea4f7 --- /dev/null +++ b/react-text-align/src/components/editor/sample/sample-doc-text-align.ts @@ -0,0 +1,56 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Heading', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'left', + }, + content: [ + { + type: 'text', + text: 'First paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Second paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'right', + }, + content: [ + { + type: 'text', + text: 'Third paragraph', + }, + ], + }, + ], +} diff --git a/react-text-align/src/components/editor/ui/button/button.tsx b/react-text-align/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-text-align/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-text-align/src/components/editor/ui/button/index.ts b/react-text-align/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-text-align/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-text-align/src/main.tsx b/react-text-align/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-text-align/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-text-align/tsconfig.app.json b/react-text-align/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-text-align/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-text-align/tsconfig.json b/react-text-align/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-text-align/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-text-align/tsconfig.node.json b/react-text-align/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-text-align/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-text-align/vite.config.ts b/react-text-align/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-text-align/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-text-color/.gitignore b/react-text-color/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-text-color/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-text-color/README.md b/react-text-color/README.md new file mode 100644 index 0000000000..bdf7d67828 --- /dev/null +++ b/react-text-color/README.md @@ -0,0 +1,15 @@ +# react-text-color + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-text-color) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-text-color) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-text-color react-text-color +cd react-text-color +npm install +npm run dev +``` diff --git a/react-text-color/index.html b/react-text-color/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-text-color/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-text-color/package.json b/react-text-color/package.json new file mode 100644 index 0000000000..896f23f9c8 --- /dev/null +++ b/react-text-color/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-text-color", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-text-color/src/App.tsx b/react-text-color/src/App.tsx new file mode 100644 index 0000000000..1225de322a --- /dev/null +++ b/react-text-color/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/text-color' + +export default function App() { + return +} diff --git a/react-text-color/src/app.css b/react-text-color/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-text-color/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-text-color/src/components/editor/examples/text-color/editor.tsx b/react-text-color/src/components/editor/examples/text-color/editor.tsx new file mode 100644 index 0000000000..ce38555707 --- /dev/null +++ b/react-text-color/src/components/editor/examples/text-color/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-text-color' + +import { defineExtension } from './extension' +import InlineMenu from './inline-menu' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/react-text-color/src/components/editor/examples/text-color/extension.ts b/react-text-color/src/components/editor/examples/text-color/extension.ts new file mode 100644 index 0000000000..d35d9d5c22 --- /dev/null +++ b/react-text-color/src/components/editor/examples/text-color/extension.ts @@ -0,0 +1,14 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineBackgroundColor } from 'prosekit/extensions/background-color' +import { defineTextColor } from 'prosekit/extensions/text-color' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextColor(), + defineBackgroundColor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-text-color/src/components/editor/examples/text-color/index.ts b/react-text-color/src/components/editor/examples/text-color/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-text-color/src/components/editor/examples/text-color/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-text-color/src/components/editor/examples/text-color/inline-menu.tsx b/react-text-color/src/components/editor/examples/text-color/inline-menu.tsx new file mode 100644 index 0000000000..727551341c --- /dev/null +++ b/react-text-color/src/components/editor/examples/text-color/inline-menu.tsx @@ -0,0 +1,147 @@ +'use client' + +import type { Editor, Keymap } from 'prosekit/core' +import { useEditorDerivedValue, useKeymap } from 'prosekit/react' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/react/inline-popover' +import { useMemo, useState } from 'react' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +const textColors = [ + { label: 'Gray', value: '#9ca3af' }, + { label: 'Brown', value: '#92400e' }, + { label: 'Orange', value: '#ea580c' }, + { label: 'Yellow', value: '#ca8a04' }, + { label: 'Green', value: '#16a34a' }, + { label: 'Blue', value: '#2563eb' }, + { label: 'Purple', value: '#9333ea' }, + { label: 'Magenta', value: '#c026d3' }, + { label: 'Red', value: '#dc2626' }, +] + +const backgroundColors = [ + { label: 'Gray', value: '#f3f4f6' }, + { label: 'Brown', value: '#fef3c7' }, + { label: 'Orange', value: '#ffedd5' }, + { label: 'Yellow', value: '#fef9c3' }, + { label: 'Green', value: '#d1fae5' }, + { label: 'Blue', value: '#dbeafe' }, + { label: 'Purple', value: '#e9d5ff' }, + { label: 'Pink', value: '#fce7f3' }, + { label: 'Red', value: '#fecaca' }, +] + +function getTextColorState(editor: Editor) { + return [ + { + label: 'Default', + value: 'currentColor', + isActive: !editor.marks.textColor.isActive(), + onClick: () => editor.commands.removeTextColor(), + }, + ].concat( + textColors.map((color) => ({ + label: color.label, + value: color.value, + isActive: editor.marks.textColor.isActive({ color: color.value }), + onClick: () => editor.commands.addTextColor({ color: color.value }), + })), + ) +} + +function getBackgroundColorState(editor: Editor) { + return [ + { + label: 'Default', + value: 'canvas', + isActive: !editor.marks.backgroundColor.isActive(), + onClick: () => editor.commands.removeBackgroundColor(), + }, + ].concat( + backgroundColors.map((color) => ({ + label: color.label, + value: color.value, + isActive: editor.marks.backgroundColor.isActive({ color: color.value }), + onClick: () => editor.commands.addBackgroundColor({ color: color.value }), + })), + ) +} + +export default function InlineMenu() { + const textColorState = useEditorDerivedValue(getTextColorState) + const backgroundColorState = useEditorDerivedValue(getBackgroundColorState) + const [open, setOpen] = useState(false) + + const keymap: Keymap = useMemo( + () => ({ + Escape: () => { + if (open) { + setOpen(false) + return true + } + return false + }, + }), + [open], + ) + + useKeymap(keymap) + + return ( + setOpen(event.detail)} + > + + +
+
+
Text color
+
+ {textColorState.map((color) => ( + + ))} +
+
+
+
Background color
+
+ {backgroundColorState.map((color) => ( + + ))} +
+
+
+
+
+
+ ) +} diff --git a/react-text-color/src/components/editor/sample/sample-doc-text-color.ts b/react-text-color/src/components/editor/sample/sample-doc-text-color.ts new file mode 100644 index 0000000000..a4efe4308d --- /dev/null +++ b/react-text-color/src/components/editor/sample/sample-doc-text-color.ts @@ -0,0 +1,120 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#ef4444', + }, + }, + ], + text: 'Select', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#f97316', + }, + }, + ], + text: 'some', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#eab308', + }, + }, + ], + text: 'text', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#22c55e', + }, + }, + ], + text: 'to', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#3b82f6', + }, + }, + ], + text: 'change', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#6366f1', + }, + }, + ], + text: 'the', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#a855f7', + }, + }, + ], + text: 'color', + }, + ], + }, + ], +} diff --git a/react-text-color/src/components/editor/ui/button/button.tsx b/react-text-color/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-text-color/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-text-color/src/components/editor/ui/button/index.ts b/react-text-color/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-text-color/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-text-color/src/main.tsx b/react-text-color/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-text-color/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-text-color/tsconfig.app.json b/react-text-color/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-text-color/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-text-color/tsconfig.json b/react-text-color/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-text-color/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-text-color/tsconfig.node.json b/react-text-color/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-text-color/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-text-color/vite.config.ts b/react-text-color/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-text-color/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-toolbar/.gitignore b/react-toolbar/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-toolbar/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-toolbar/README.md b/react-toolbar/README.md new file mode 100644 index 0000000000..7da35f4c31 --- /dev/null +++ b/react-toolbar/README.md @@ -0,0 +1,15 @@ +# react-toolbar + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-toolbar) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-toolbar) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-toolbar react-toolbar +cd react-toolbar +npm install +npm run dev +``` diff --git a/react-toolbar/index.html b/react-toolbar/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-toolbar/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-toolbar/package.json b/react-toolbar/package.json new file mode 100644 index 0000000000..1ce0edaca4 --- /dev/null +++ b/react-toolbar/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-toolbar", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-toolbar/src/App.tsx b/react-toolbar/src/App.tsx new file mode 100644 index 0000000000..72699e4f11 --- /dev/null +++ b/react-toolbar/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/toolbar' + +export default function App() { + return +} diff --git a/react-toolbar/src/app.css b/react-toolbar/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-toolbar/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-toolbar/src/components/editor/examples/toolbar/editor.tsx b/react-toolbar/src/components/editor/examples/toolbar/editor.tsx new file mode 100644 index 0000000000..d15dcd9ff4 --- /dev/null +++ b/react-toolbar/src/components/editor/examples/toolbar/editor.tsx @@ -0,0 +1,34 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleUploader } from '../../sample/sample-uploader' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-toolbar/src/components/editor/examples/toolbar/extension.ts b/react-toolbar/src/components/editor/examples/toolbar/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/react-toolbar/src/components/editor/examples/toolbar/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/react-toolbar/src/components/editor/examples/toolbar/index.ts b/react-toolbar/src/components/editor/examples/toolbar/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-toolbar/src/components/editor/examples/toolbar/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-toolbar/src/components/editor/sample/sample-uploader.ts b/react-toolbar/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/react-toolbar/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/react-toolbar/src/components/editor/ui/button/button.tsx b/react-toolbar/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-toolbar/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-toolbar/src/components/editor/ui/button/index.ts b/react-toolbar/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-toolbar/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/react-toolbar/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-toolbar/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-toolbar/src/components/editor/ui/toolbar/index.ts b/react-toolbar/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-toolbar/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-toolbar/src/components/editor/ui/toolbar/toolbar.tsx b/react-toolbar/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-toolbar/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-toolbar/src/main.tsx b/react-toolbar/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-toolbar/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-toolbar/tsconfig.app.json b/react-toolbar/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-toolbar/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-toolbar/tsconfig.json b/react-toolbar/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-toolbar/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-toolbar/tsconfig.node.json b/react-toolbar/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-toolbar/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-toolbar/vite.config.ts b/react-toolbar/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-toolbar/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-tweet/.gitignore b/react-tweet/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-tweet/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-tweet/README.md b/react-tweet/README.md new file mode 100644 index 0000000000..93a6990cf6 --- /dev/null +++ b/react-tweet/README.md @@ -0,0 +1,15 @@ +# react-tweet + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-tweet) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-tweet) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-tweet react-tweet +cd react-tweet +npm install +npm run dev +``` diff --git a/react-tweet/index.html b/react-tweet/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-tweet/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-tweet/package.json b/react-tweet/package.json new file mode 100644 index 0000000000..ec5b312a5e --- /dev/null +++ b/react-tweet/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-react-tweet", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "react-tweet": "^3.3.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-tweet/src/App.tsx b/react-tweet/src/App.tsx new file mode 100644 index 0000000000..f958ff180a --- /dev/null +++ b/react-tweet/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/tweet' + +export default function App() { + return +} diff --git a/react-tweet/src/app.css b/react-tweet/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-tweet/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-tweet/src/components/editor/examples/tweet/editor.tsx b/react-tweet/src/components/editor/examples/tweet/editor.tsx new file mode 100644 index 0000000000..a0a3a809a9 --- /dev/null +++ b/react-tweet/src/components/editor/examples/tweet/editor.tsx @@ -0,0 +1,53 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type Extension, type NodeJSON } from 'prosekit/core' +import { defineReactNodeView, ProseKit, useExtension } from 'prosekit/react' +import { useMemo, useState } from 'react' + +import { sampleContent } from '../../sample/sample-doc-tweet' + +import { defineExtension } from './extension' +import { MethodSelect } from './method-select' +import { TweetView } from './tweet-view' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + return createEditor({ extension: defineExtension(), defaultContent }) + }, [defaultContent]) + + const [method, setMethod] = useState<'basic' | 'advanced'>('basic') + + const reactTweetView: Extension | null = useMemo(() => { + if (method === 'basic') { + return null + } + return defineReactNodeView({ + name: 'tweet', + component: TweetView, + }) + }, [method]) + + useExtension(reactTweetView, { editor }) + + return ( + + +
+
+
+
+
+
+ ) +} diff --git a/react-tweet/src/components/editor/examples/tweet/extension.ts b/react-tweet/src/components/editor/examples/tweet/extension.ts new file mode 100644 index 0000000000..ec730c0899 --- /dev/null +++ b/react-tweet/src/components/editor/examples/tweet/extension.ts @@ -0,0 +1,43 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { defineNodeSpec, union } from 'prosekit/core' + +function defineTweetSpec() { + return defineNodeSpec({ + name: 'tweet', + group: 'block', + attrs: { + tweetId: { default: null }, + }, + parseDOM: [ + { + tag: 'iframe[src^="https://platform.twitter.com/embed/Tweet.html"]', + getAttrs: (node) => { + const src = node.getAttribute('src') + const match = src?.match(/id=([^&]+)/) + return { + tweetId: match?.[1] ?? null, + } + }, + }, + ], + toDOM: (node) => { + return [ + 'iframe', + { + src: `https://platform.twitter.com/embed/Tweet.html?id=${node.attrs.tweetId}&theme=dark`, + style: 'height: 300px', + }, + ] + }, + }) +} + +function defineTweet() { + return union(defineTweetSpec()) +} + +export function defineExtension() { + return union(defineBasicExtension(), defineTweet()) +} + +export type EditorExtension = ReturnType diff --git a/react-tweet/src/components/editor/examples/tweet/index.ts b/react-tweet/src/components/editor/examples/tweet/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-tweet/src/components/editor/examples/tweet/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-tweet/src/components/editor/examples/tweet/method-select.tsx b/react-tweet/src/components/editor/examples/tweet/method-select.tsx new file mode 100644 index 0000000000..ceaf4cce13 --- /dev/null +++ b/react-tweet/src/components/editor/examples/tweet/method-select.tsx @@ -0,0 +1,42 @@ +'use client' + +import { useId } from 'react' + +export function MethodSelect(props: { + value: 'basic' | 'advanced' + onChange: (value: 'basic' | 'advanced') => void +}) { + const id = 'id-' + useId() + const basicId = `${id}-basic` + const advancedId = `${id}-advanced` + + return ( +
+ Select a render method: + +
+ props.onChange('basic')} + /> + +
+ +
+ props.onChange('advanced')} + /> + +
+
+ ) +} diff --git a/react-tweet/src/components/editor/examples/tweet/tweet-view.tsx b/react-tweet/src/components/editor/examples/tweet/tweet-view.tsx new file mode 100644 index 0000000000..78d1313ac8 --- /dev/null +++ b/react-tweet/src/components/editor/examples/tweet/tweet-view.tsx @@ -0,0 +1,27 @@ +'use client' + +import type { ReactNodeViewProps } from 'prosekit/react' +import { Tweet } from 'react-tweet' + +export function TweetView({ node }: ReactNodeViewProps) { + const tweetId = node.attrs.tweetId as string + return ( +
+
+ + Rendered in React using library{' '} + + + react-tweet + + + +
+ +
+ ) +} diff --git a/react-tweet/src/components/editor/sample/sample-doc-tweet.ts b/react-tweet/src/components/editor/sample/sample-doc-tweet.ts new file mode 100644 index 0000000000..f0c0e6ca60 --- /dev/null +++ b/react-tweet/src/components/editor/sample/sample-doc-tweet.ts @@ -0,0 +1,22 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Render a tweet in your document', + }, + ], + }, + { + type: 'tweet', + attrs: { + tweetId: '20', + }, + }, + ], +} diff --git a/react-tweet/src/main.tsx b/react-tweet/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-tweet/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-tweet/tsconfig.app.json b/react-tweet/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-tweet/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-tweet/tsconfig.json b/react-tweet/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-tweet/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-tweet/tsconfig.node.json b/react-tweet/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-tweet/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-tweet/vite.config.ts b/react-tweet/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-tweet/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-typography/.gitignore b/react-typography/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-typography/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-typography/README.md b/react-typography/README.md new file mode 100644 index 0000000000..f57c81da83 --- /dev/null +++ b/react-typography/README.md @@ -0,0 +1,15 @@ +# react-typography + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-typography) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-typography) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-typography react-typography +cd react-typography +npm install +npm run dev +``` diff --git a/react-typography/index.html b/react-typography/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-typography/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-typography/package.json b/react-typography/package.json new file mode 100644 index 0000000000..637213e668 --- /dev/null +++ b/react-typography/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-react-typography", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-typography/src/App.tsx b/react-typography/src/App.tsx new file mode 100644 index 0000000000..e1a59aa483 --- /dev/null +++ b/react-typography/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/typography' + +export default function App() { + return +} diff --git a/react-typography/src/app.css b/react-typography/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-typography/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-typography/src/components/editor/examples/typography/editor.tsx b/react-typography/src/components/editor/examples/typography/editor.tsx new file mode 100644 index 0000000000..94f229b751 --- /dev/null +++ b/react-typography/src/components/editor/examples/typography/editor.tsx @@ -0,0 +1,41 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-typography' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/react-typography/src/components/editor/examples/typography/extension.ts b/react-typography/src/components/editor/examples/typography/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/react-typography/src/components/editor/examples/typography/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-typography/src/components/editor/examples/typography/index.ts b/react-typography/src/components/editor/examples/typography/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-typography/src/components/editor/examples/typography/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-typography/src/components/editor/sample/katex.ts b/react-typography/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/react-typography/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/react-typography/src/components/editor/sample/sample-doc-typography.ts b/react-typography/src/components/editor/sample/sample-doc-typography.ts new file mode 100644 index 0000000000..db18b8155c --- /dev/null +++ b/react-typography/src/components/editor/sample/sample-doc-typography.ts @@ -0,0 +1,693 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'ProseKit Typography', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This example shows the typography styles provided by ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'prosekit/basic/typography.css', + }, + { + type: 'text', + text: '.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Inline marks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Text can be formatted in different ways: ', + }, + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'bold text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'italic text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'underlined text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'strikethrough text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'inline code', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://example.com', + target: null, + rel: null, + }, + }, + ], + text: 'links', + }, + { + type: 'text', + text: ',', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'and hard breaks (Shift+Enter).', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Headings', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Heading 1', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Heading 2', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Heading 3', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 4, + }, + content: [ + { + type: 'text', + text: 'Heading 4', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 5, + }, + content: [ + { + type: 'text', + text: 'Heading 5', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 6, + }, + content: [ + { + type: 'text', + text: 'Heading 6', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Lists', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here are different types of lists:', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 1', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 2', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item A', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item B', + }, + ], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'First ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Second ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: true, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Completed task', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Pending task', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Blockquotes', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: '', + }, + content: [ + { + type: 'text', + text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Horizontal Rule', + }, + ], + }, + { + type: 'horizontalRule', + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blurred/640x360/42', + }, + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Tables', + }, + ], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 1', + }, + ], + }, + ], + }, + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 3', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 4', + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Math', + }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Inline math like Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text.' }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Block-level equations are displayed on their own line:', + }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + ], +} diff --git a/react-typography/src/components/editor/ui/block-handle/block-handle.tsx b/react-typography/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..3cc6028d5c --- /dev/null +++ b/react-typography/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,33 @@ +'use client' + +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/react/block-handle' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props) { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/react-typography/src/components/editor/ui/block-handle/index.ts b/react-typography/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/react-typography/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/react-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/react-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx new file mode 100644 index 0000000000..87c1746622 --- /dev/null +++ b/react-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx @@ -0,0 +1,7 @@ +'use client' + +import { DropIndicator as BaseDropIndicator } from 'prosekit/react/drop-indicator' + +export default function DropIndicator() { + return +} diff --git a/react-typography/src/components/editor/ui/drop-indicator/index.ts b/react-typography/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..f8fb7139c4 --- /dev/null +++ b/react-typography/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator' diff --git a/react-typography/src/main.tsx b/react-typography/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-typography/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-typography/tsconfig.app.json b/react-typography/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-typography/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-typography/tsconfig.json b/react-typography/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-typography/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-typography/tsconfig.node.json b/react-typography/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-typography/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-typography/vite.config.ts b/react-typography/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-typography/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-underline/.gitignore b/react-underline/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-underline/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-underline/README.md b/react-underline/README.md new file mode 100644 index 0000000000..2686efd803 --- /dev/null +++ b/react-underline/README.md @@ -0,0 +1,15 @@ +# react-underline + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-underline) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-underline) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-underline react-underline +cd react-underline +npm install +npm run dev +``` diff --git a/react-underline/index.html b/react-underline/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-underline/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-underline/package.json b/react-underline/package.json new file mode 100644 index 0000000000..f090213bf3 --- /dev/null +++ b/react-underline/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-underline", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-underline/src/App.tsx b/react-underline/src/App.tsx new file mode 100644 index 0000000000..6a03ee7870 --- /dev/null +++ b/react-underline/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/underline' + +export default function App() { + return +} diff --git a/react-underline/src/app.css b/react-underline/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-underline/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-underline/src/components/editor/examples/underline/editor.tsx b/react-underline/src/components/editor/examples/underline/editor.tsx new file mode 100644 index 0000000000..a53df8f9d7 --- /dev/null +++ b/react-underline/src/components/editor/examples/underline/editor.tsx @@ -0,0 +1,39 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-underline' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension, defaultContent }) + }, [defaultContent]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-underline/src/components/editor/examples/underline/extension.ts b/react-underline/src/components/editor/examples/underline/extension.ts new file mode 100644 index 0000000000..16a9b58284 --- /dev/null +++ b/react-underline/src/components/editor/examples/underline/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineUnderline(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-underline/src/components/editor/examples/underline/index.ts b/react-underline/src/components/editor/examples/underline/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-underline/src/components/editor/examples/underline/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-underline/src/components/editor/sample/sample-doc-underline.ts b/react-underline/src/components/editor/sample/sample-doc-underline.ts new file mode 100644 index 0000000000..6af561064b --- /dev/null +++ b/react-underline/src/components/editor/sample/sample-doc-underline.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'This is underline', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/react-underline/src/components/editor/ui/button/button.tsx b/react-underline/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-underline/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-underline/src/components/editor/ui/button/index.ts b/react-underline/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-underline/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-underline/src/components/editor/ui/image-upload-popover/index.ts b/react-underline/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-underline/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-underline/src/components/editor/ui/toolbar/index.ts b/react-underline/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-underline/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-underline/src/components/editor/ui/toolbar/toolbar.tsx b/react-underline/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-underline/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-underline/src/main.tsx b/react-underline/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-underline/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-underline/tsconfig.app.json b/react-underline/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-underline/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-underline/tsconfig.json b/react-underline/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-underline/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-underline/tsconfig.node.json b/react-underline/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-underline/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-underline/vite.config.ts b/react-underline/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-underline/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-unmount/.gitignore b/react-unmount/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-unmount/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-unmount/README.md b/react-unmount/README.md new file mode 100644 index 0000000000..bc8713cc6a --- /dev/null +++ b/react-unmount/README.md @@ -0,0 +1,15 @@ +# react-unmount + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-unmount) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-unmount) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-unmount react-unmount +cd react-unmount +npm install +npm run dev +``` diff --git a/react-unmount/index.html b/react-unmount/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-unmount/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-unmount/package.json b/react-unmount/package.json new file mode 100644 index 0000000000..e728681abe --- /dev/null +++ b/react-unmount/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-unmount", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-unmount/src/App.tsx b/react-unmount/src/App.tsx new file mode 100644 index 0000000000..da35bea56f --- /dev/null +++ b/react-unmount/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/unmount' + +export default function App() { + return +} diff --git a/react-unmount/src/app.css b/react-unmount/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-unmount/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-unmount/src/components/editor/examples/unmount/editor-component.tsx b/react-unmount/src/components/editor/examples/unmount/editor-component.tsx new file mode 100644 index 0000000000..dac49ebeaa --- /dev/null +++ b/react-unmount/src/components/editor/examples/unmount/editor-component.tsx @@ -0,0 +1,34 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { InlineMenu } from '../../ui/inline-menu' + +import ExtensionComponent from './extension-component' + +export default function EditorComponent(props: { placeholder: string }) { + const editor = useMemo(() => { + return createEditor({ extension: defineBasicExtension() }) + }, []) + + return ( + +
+
+
+ +
+
+ +
+ ) +} diff --git a/react-unmount/src/components/editor/examples/unmount/editor.tsx b/react-unmount/src/components/editor/examples/unmount/editor.tsx new file mode 100644 index 0000000000..c970e2961c --- /dev/null +++ b/react-unmount/src/components/editor/examples/unmount/editor.tsx @@ -0,0 +1,46 @@ +'use client' + +import { useCallback, useRef, useState } from 'react' + +import EditorComponent from './editor-component' + +function EditorGroup() { + const nextKeyRef = useRef(1) + const [editorKeys, setEditorKeys] = useState([]) + + const addEditor = useCallback(() => { + const key = nextKeyRef.current + nextKeyRef.current += 1 + setEditorKeys((keys) => [...keys, key]) + }, []) + + const removeEditor = useCallback((key: number) => { + setEditorKeys((keys) => keys.filter((k) => k !== key)) + }, []) + + return ( +
+
+ + {editorKeys.map((key) => ( + + ))} +
+ {editorKeys.map((key) => ( +
+ +
+ ))} +
+ ) +} + +export default EditorGroup diff --git a/react-unmount/src/components/editor/examples/unmount/extension-component.tsx b/react-unmount/src/components/editor/examples/unmount/extension-component.tsx new file mode 100644 index 0000000000..54dcf9e0b0 --- /dev/null +++ b/react-unmount/src/components/editor/examples/unmount/extension-component.tsx @@ -0,0 +1,16 @@ +'use client' + +import { definePlaceholder } from 'prosekit/extensions/placeholder' +import { useExtension } from 'prosekit/react' +import { useMemo } from 'react' + +export default function ExtensionComponent(props: { placeholder: string }) { + const extension = useMemo( + () => definePlaceholder({ placeholder: props.placeholder }), + [props.placeholder], + ) + + useExtension(extension) + + return null +} diff --git a/react-unmount/src/components/editor/examples/unmount/index.ts b/react-unmount/src/components/editor/examples/unmount/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-unmount/src/components/editor/examples/unmount/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-unmount/src/components/editor/ui/button/button.tsx b/react-unmount/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-unmount/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-unmount/src/components/editor/ui/button/index.ts b/react-unmount/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-unmount/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-unmount/src/components/editor/ui/inline-menu/index.ts b/react-unmount/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/react-unmount/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/react-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx b/react-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..af1b2bb2b7 --- /dev/null +++ b/react-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,221 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/react' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/react/inline-popover' +import { useState } from 'react' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu() { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = useState(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor.commands.addLink({ href }) + } else { + editor.commands.removeLink() + } + + setLinkMenuOpen(false) + editor.focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.link && items.link.canExec && ( + + )} + + + + + {items.link && ( + setLinkMenuOpen(event.detail)} + > + + + {linkMenuOpen && ( +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ )} + {items.link.isActive && ( + + )} +
+
+
+ )} + + ) +} diff --git a/react-unmount/src/main.tsx b/react-unmount/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-unmount/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-unmount/tsconfig.app.json b/react-unmount/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-unmount/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-unmount/tsconfig.json b/react-unmount/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-unmount/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-unmount/tsconfig.node.json b/react-unmount/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-unmount/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-unmount/vite.config.ts b/react-unmount/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-unmount/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-user-menu-dynamic/.gitignore b/react-user-menu-dynamic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-user-menu-dynamic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-user-menu-dynamic/README.md b/react-user-menu-dynamic/README.md new file mode 100644 index 0000000000..a37811c5c5 --- /dev/null +++ b/react-user-menu-dynamic/README.md @@ -0,0 +1,15 @@ +# react-user-menu-dynamic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-user-menu-dynamic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-user-menu-dynamic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-user-menu-dynamic react-user-menu-dynamic +cd react-user-menu-dynamic +npm install +npm run dev +``` diff --git a/react-user-menu-dynamic/index.html b/react-user-menu-dynamic/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-user-menu-dynamic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-user-menu-dynamic/package.json b/react-user-menu-dynamic/package.json new file mode 100644 index 0000000000..45287eed9d --- /dev/null +++ b/react-user-menu-dynamic/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-user-menu-dynamic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-user-menu-dynamic/src/App.tsx b/react-user-menu-dynamic/src/App.tsx new file mode 100644 index 0000000000..e3ec0e7b10 --- /dev/null +++ b/react-user-menu-dynamic/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/user-menu-dynamic' + +export default function App() { + return +} diff --git a/react-user-menu-dynamic/src/app.css b/react-user-menu-dynamic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-user-menu-dynamic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx new file mode 100644 index 0000000000..966c2b115e --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx @@ -0,0 +1,32 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { defineExtension } from './extension' +import UserMenuDynamic from './user-menu-dynamic' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts new file mode 100644 index 0000000000..ff2c40b104 --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts new file mode 100644 index 0000000000..0d2151d2b0 --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts @@ -0,0 +1,40 @@ +import { useEffect, useState } from 'react' + +import type { User } from '../../sample/sample-query-users' +import { queryUsers } from '../../sample/sample-query-users' + +/** + * Simulate a user searching with some delay. + */ +export function useUserQuery(query: string, enabled: boolean) { + const [users, setUsers] = useState([]) + const [loading, setLoading] = useState(true) + + if (!enabled && users.length > 0) { + setUsers([]) + } + + useEffect(() => { + if (!enabled) { + return + } + + let cancelled = false + + void (async () => { + setLoading(true) + const filteredUsers = await queryUsers(query) + if (cancelled) { + return + } + setUsers(filteredUsers) + setLoading(false) + })() + + return () => { + cancelled = true + } + }, [enabled, query]) + + return { loading, users } +} diff --git a/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx new file mode 100644 index 0000000000..2e873dca40 --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx @@ -0,0 +1,23 @@ +'use client' + +import { useState } from 'react' + +import { UserMenu } from '../../ui/user-menu' + +import { useUserQuery } from './use-user-query' + +export default function UserMenuDynamic() { + const [query, setQuery] = useState('') + const [open, setOpen] = useState(false) + + const { loading, users } = useUserQuery(query, open) + + return ( + + ) +} diff --git a/react-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/react-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts new file mode 100644 index 0000000000..ab78fd5525 --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts @@ -0,0 +1,40 @@ +import { users } from './sample-user-data' + +export interface User { + id: number + name: string +} + +const connectHandlers: VoidFunction[] = [] +let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' + +/** + * A utility function to simulate different network states. Useful for testing. + * + * @internal + */ +export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { + networkStatus = status + if (status !== 'offline') { + connectHandlers.forEach((handler) => handler()) + connectHandlers.length = 0 + } +} + +/** + * Simulate a user searching with some delay. + */ +export async function queryUsers(query: string): Promise { + if (networkStatus === 'offline') { + await new Promise((resolve) => connectHandlers.push(resolve)) + } + if (networkStatus === 'slow') { + await new Promise((resolve) => setTimeout(resolve, 300)) + } + + const normalizedQuery = query.toLowerCase().trim() + const filteredUsers = users + .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) + .slice(0, 10) + return filteredUsers +} diff --git a/react-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/react-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/react-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/react-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/react-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx b/react-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..46555f6382 --- /dev/null +++ b/react-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,64 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/react' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}) { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + {props.users.map((user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + ))} +
+
+
+
+ ) +} diff --git a/react-user-menu-dynamic/src/main.tsx b/react-user-menu-dynamic/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-user-menu-dynamic/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-user-menu-dynamic/tsconfig.app.json b/react-user-menu-dynamic/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-user-menu-dynamic/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-user-menu-dynamic/tsconfig.json b/react-user-menu-dynamic/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-user-menu-dynamic/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-user-menu-dynamic/tsconfig.node.json b/react-user-menu-dynamic/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-user-menu-dynamic/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-user-menu-dynamic/vite.config.ts b/react-user-menu-dynamic/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-user-menu-dynamic/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-user-menu/.gitignore b/react-user-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-user-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-user-menu/README.md b/react-user-menu/README.md new file mode 100644 index 0000000000..5fce6fb80e --- /dev/null +++ b/react-user-menu/README.md @@ -0,0 +1,15 @@ +# react-user-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-user-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-user-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-user-menu react-user-menu +cd react-user-menu +npm install +npm run dev +``` diff --git a/react-user-menu/index.html b/react-user-menu/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-user-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-user-menu/package.json b/react-user-menu/package.json new file mode 100644 index 0000000000..879a70750e --- /dev/null +++ b/react-user-menu/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-user-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-user-menu/src/App.tsx b/react-user-menu/src/App.tsx new file mode 100644 index 0000000000..92fca03d42 --- /dev/null +++ b/react-user-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/user-menu' + +export default function App() { + return +} diff --git a/react-user-menu/src/app.css b/react-user-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-user-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-user-menu/src/components/editor/examples/user-menu/editor.tsx b/react-user-menu/src/components/editor/examples/user-menu/editor.tsx new file mode 100644 index 0000000000..c0c8c65162 --- /dev/null +++ b/react-user-menu/src/components/editor/examples/user-menu/editor.tsx @@ -0,0 +1,37 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { tags } from '../../sample/sample-tag-data' +import { users } from '../../sample/sample-user-data' +import { TagMenu } from '../../ui/tag-menu' +import { UserMenu } from '../../ui/user-menu' + +import { defineExtension } from './extension' + +export default function Editor() { + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ extension }) + }, []) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/react-user-menu/src/components/editor/examples/user-menu/extension.ts b/react-user-menu/src/components/editor/examples/user-menu/extension.ts new file mode 100644 index 0000000000..56a97a4779 --- /dev/null +++ b/react-user-menu/src/components/editor/examples/user-menu/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone or # to tag something...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/react-user-menu/src/components/editor/examples/user-menu/index.ts b/react-user-menu/src/components/editor/examples/user-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-user-menu/src/components/editor/examples/user-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-user-menu/src/components/editor/sample/sample-tag-data.ts b/react-user-menu/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/react-user-menu/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/react-user-menu/src/components/editor/sample/sample-user-data.ts b/react-user-menu/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/react-user-menu/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/react-user-menu/src/components/editor/ui/tag-menu/index.ts b/react-user-menu/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..d344b33a70 --- /dev/null +++ b/react-user-menu/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu' diff --git a/react-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx b/react-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx new file mode 100644 index 0000000000..711486fcf7 --- /dev/null +++ b/react-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx @@ -0,0 +1,54 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/react' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +const regex = /#[\da-z]*$/i + +export default function TagMenu(props: { + tags: { id: number; label: string }[] +}) { + const editor = useEditor>() + + const handleTagInsert = (id: number, label: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '#' + label, + kind: 'tag', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + + + +
+ + No results + + + {props.tags.map((tag) => ( + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + ))} +
+
+
+
+ ) +} diff --git a/react-user-menu/src/components/editor/ui/user-menu/index.ts b/react-user-menu/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/react-user-menu/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/react-user-menu/src/components/editor/ui/user-menu/user-menu.tsx b/react-user-menu/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..46555f6382 --- /dev/null +++ b/react-user-menu/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,64 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/react' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/react/autocomplete' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}) { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor.commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor.commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + {props.users.map((user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + ))} +
+
+
+
+ ) +} diff --git a/react-user-menu/src/main.tsx b/react-user-menu/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-user-menu/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-user-menu/tsconfig.app.json b/react-user-menu/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-user-menu/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-user-menu/tsconfig.json b/react-user-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-user-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-user-menu/tsconfig.node.json b/react-user-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-user-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-user-menu/vite.config.ts b/react-user-menu/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-user-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-word-counter/.gitignore b/react-word-counter/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-word-counter/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-word-counter/README.md b/react-word-counter/README.md new file mode 100644 index 0000000000..9b868dc92e --- /dev/null +++ b/react-word-counter/README.md @@ -0,0 +1,15 @@ +# react-word-counter + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-word-counter) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-word-counter) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-word-counter react-word-counter +cd react-word-counter +npm install +npm run dev +``` diff --git a/react-word-counter/index.html b/react-word-counter/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-word-counter/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-word-counter/package.json b/react-word-counter/package.json new file mode 100644 index 0000000000..19f0b053ad --- /dev/null +++ b/react-word-counter/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-react-word-counter", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-word-counter/src/App.tsx b/react-word-counter/src/App.tsx new file mode 100644 index 0000000000..9da98dddb5 --- /dev/null +++ b/react-word-counter/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/word-counter' + +export default function App() { + return +} diff --git a/react-word-counter/src/app.css b/react-word-counter/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-word-counter/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-word-counter/src/components/editor/examples/word-counter/editor.tsx b/react-word-counter/src/components/editor/examples/word-counter/editor.tsx new file mode 100644 index 0000000000..3928af8804 --- /dev/null +++ b/react-word-counter/src/components/editor/examples/word-counter/editor.tsx @@ -0,0 +1,42 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' + +import { sampleContent } from '../../sample/sample-doc-word-counter' +import { WordCounter } from '../../ui/word-counter' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps) { + const defaultContent = props.initialContent ?? sampleContent + const editor = useMemo(() => { + const extension = defineExtension() + return createEditor({ + extension, + defaultContent, + }) + }, [defaultContent]) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/react-word-counter/src/components/editor/examples/word-counter/extension.ts b/react-word-counter/src/components/editor/examples/word-counter/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/react-word-counter/src/components/editor/examples/word-counter/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/react-word-counter/src/components/editor/examples/word-counter/index.ts b/react-word-counter/src/components/editor/examples/word-counter/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-word-counter/src/components/editor/examples/word-counter/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/react-word-counter/src/components/editor/sample/sample-doc-word-counter.ts new file mode 100644 index 0000000000..0b5d435038 --- /dev/null +++ b/react-word-counter/src/components/editor/sample/sample-doc-word-counter.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Start typing and observe the word count update below.', + }, + ], + }, + ], +} diff --git a/react-word-counter/src/components/editor/ui/word-counter/index.ts b/react-word-counter/src/components/editor/ui/word-counter/index.ts new file mode 100644 index 0000000000..929ee3e41a --- /dev/null +++ b/react-word-counter/src/components/editor/ui/word-counter/index.ts @@ -0,0 +1 @@ +export { default as WordCounter } from './word-counter' diff --git a/react-word-counter/src/components/editor/ui/word-counter/word-counter.tsx b/react-word-counter/src/components/editor/ui/word-counter/word-counter.tsx new file mode 100644 index 0000000000..24407adc3b --- /dev/null +++ b/react-word-counter/src/components/editor/ui/word-counter/word-counter.tsx @@ -0,0 +1,24 @@ +'use client' + +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/react' + +function getWordCount(editor: Editor) { + const doc = editor.state.doc + const words = doc ? doc.textBetween(0, doc.content.size, ' ') : '' + const wordCount = words.split(/\s+/).filter((s) => s).length + const characterCount = doc ? doc.textContent.length : 0 + return { wordCount, characterCount } +} + +export default function WordCounter() { + const { wordCount, characterCount } = useEditorDerivedValue(getWordCount) + + return ( +
+ Word Count: {wordCount} +
+ Character Count: {characterCount} +
+ ) +} diff --git a/react-word-counter/src/main.tsx b/react-word-counter/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-word-counter/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-word-counter/tsconfig.app.json b/react-word-counter/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-word-counter/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-word-counter/tsconfig.json b/react-word-counter/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-word-counter/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-word-counter/tsconfig.node.json b/react-word-counter/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-word-counter/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-word-counter/vite.config.ts b/react-word-counter/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-word-counter/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/react-yjs/.gitignore b/react-yjs/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/react-yjs/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/react-yjs/README.md b/react-yjs/README.md new file mode 100644 index 0000000000..d9790248f2 --- /dev/null +++ b/react-yjs/README.md @@ -0,0 +1,15 @@ +# react-yjs + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/react-yjs) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/react-yjs) + +Run the example locally with: + +```bash +npx degit prosekit/examples/react-yjs react-yjs +cd react-yjs +npm install +npm run dev +``` diff --git a/react-yjs/index.html b/react-yjs/index.html new file mode 100644 index 0000000000..a5a78f3bf8 --- /dev/null +++ b/react-yjs/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + React + + +
+ + + diff --git a/react-yjs/package.json b/react-yjs/package.json new file mode 100644 index 0000000000..f9572923b8 --- /dev/null +++ b/react-yjs/package.json @@ -0,0 +1,31 @@ +{ + "name": "example-react-yjs", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "react": "^19.2.6", + "react-dom": "^19.2.6", + "y-prosemirror": "^1.3.7", + "y-websocket": "^3.0.0", + "yjs": "^13.6.30" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@types/react": "^19.2.14", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/react-yjs/src/App.tsx b/react-yjs/src/App.tsx new file mode 100644 index 0000000000..8641aefe47 --- /dev/null +++ b/react-yjs/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/yjs' + +export default function App() { + return +} diff --git a/react-yjs/src/app.css b/react-yjs/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/react-yjs/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/react-yjs/src/components/editor/examples/yjs/editor-component.tsx b/react-yjs/src/components/editor/examples/yjs/editor-component.tsx new file mode 100644 index 0000000000..c35b61ad0a --- /dev/null +++ b/react-yjs/src/components/editor/examples/yjs/editor-component.tsx @@ -0,0 +1,43 @@ +'use client' + +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/yjs/style.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/react' +import { useMemo } from 'react' +import { WebsocketProvider } from 'y-websocket' +import * as Y from 'yjs' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function EditorComponent(props: { room?: string }) { + const editor = useMemo(() => { + const doc = new Y.Doc() + const provider = new WebsocketProvider( + 'wss://demos.yjs.dev/ws', + `github.com/prosekit/room_${props.room}`, + doc, + ) + + const extension = defineExtension(doc, provider.awareness) + return createEditor({ extension }) + }, [props.room]) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/react-yjs/src/components/editor/examples/yjs/editor.tsx b/react-yjs/src/components/editor/examples/yjs/editor.tsx new file mode 100644 index 0000000000..a7c8a5d94b --- /dev/null +++ b/react-yjs/src/components/editor/examples/yjs/editor.tsx @@ -0,0 +1,18 @@ +'use client' + +import { useState } from 'react' + +import EditorComponent from './editor-component' + +export default function Page() { + const [room] = useState(() => { + return Math.random().toString(36).substring(2, 15) + }) + + return ( +
+ + +
+ ) +} diff --git a/react-yjs/src/components/editor/examples/yjs/extension.ts b/react-yjs/src/components/editor/examples/yjs/extension.ts new file mode 100644 index 0000000000..f1a581932b --- /dev/null +++ b/react-yjs/src/components/editor/examples/yjs/extension.ts @@ -0,0 +1,48 @@ +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' +import { defineYjs } from 'prosekit/extensions/yjs' +import type { Awareness } from 'prosekit/extensions/yjs' +import type * as Y from 'yjs' + +export function defineExtension(doc: Y.Doc, awareness: Awareness) { + return union([ + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineYjs({ doc, awareness }), + ]) +} + +export type EditorExtension = ReturnType diff --git a/react-yjs/src/components/editor/examples/yjs/index.ts b/react-yjs/src/components/editor/examples/yjs/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/react-yjs/src/components/editor/examples/yjs/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/react-yjs/src/components/editor/ui/button/button.tsx b/react-yjs/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a9d125a429 --- /dev/null +++ b/react-yjs/src/components/editor/ui/button/button.tsx @@ -0,0 +1,46 @@ +'use client' + +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/react/tooltip' +import type { MouseEventHandler, ReactNode } from 'react' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: MouseEventHandler + tooltip?: string + children: ReactNode +}) { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/react-yjs/src/components/editor/ui/button/index.ts b/react-yjs/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/react-yjs/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/react-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/react-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..808361b6ad --- /dev/null +++ b/react-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,145 @@ +'use client' + +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/react' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/react/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { useId, useState, type ReactNode } from 'react' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: ReactNode +}) { + const [open, setOpen] = useState(false) + const [url, setUrl] = useState('') + const [file, setFile] = useState(null) + const ariaId = useId() + + const editor = useEditor() + + const handleFileChange: React.ChangeEventHandler = ( + event, + ) => { + const file = event.target.files?.[0] + + if (file) { + setFile(file) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange: React.ChangeEventHandler = ( + event, + ) => { + const url = event.target.value + + if (url) { + setUrl(url) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url) { + editor.commands.insertImage({ src: url }) + } else if (file) { + editor.commands.uploadImage({ file, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + {file ? null : ( + <> + + + + )} + + {url ? null : ( + <> + + + + )} + + {url ? ( + + ) : null} + + {file ? ( + + ) : null} + + + + ) +} diff --git a/react-yjs/src/components/editor/ui/image-upload-popover/index.ts b/react-yjs/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/react-yjs/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/react-yjs/src/components/editor/ui/toolbar/index.ts b/react-yjs/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/react-yjs/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/react-yjs/src/components/editor/ui/toolbar/toolbar.tsx b/react-yjs/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ce61a2d041 --- /dev/null +++ b/react-yjs/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,365 @@ +'use client' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/react' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { uploader?: Uploader }) { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ {items.undo && ( + + )} + {items.redo && ( + + )} + + {items.bold && ( + + )} + {items.italic && ( + + )} + {items.underline && ( + + )} + {items.strike && ( + + )} + {items.code && ( + + )} + {items.codeBlock && ( + + )} + {items.heading1 && ( + + )} + {items.heading2 && ( + + )} + {items.heading3 && ( + + )} + {items.horizontalRule && ( + + )} + {items.blockquote && ( + + )} + {items.bulletList && ( + + )} + {items.orderedList && ( + + )} + {items.taskList && ( + + )} + {items.toggleList && ( + + )} + {items.indentList && ( + + )} + {items.dedentList && ( + + )} + {props.uploader && items.insertImage && ( + +
+ + )} +
+ ) +} diff --git a/react-yjs/src/main.tsx b/react-yjs/src/main.tsx new file mode 100644 index 0000000000..87de8eb52b --- /dev/null +++ b/react-yjs/src/main.tsx @@ -0,0 +1,10 @@ +import './app.css' +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/react-yjs/tsconfig.app.json b/react-yjs/tsconfig.app.json new file mode 100644 index 0000000000..a9b5a59ca6 --- /dev/null +++ b/react-yjs/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/react-yjs/tsconfig.json b/react-yjs/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/react-yjs/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/react-yjs/tsconfig.node.json b/react-yjs/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/react-yjs/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/react-yjs/vite.config.ts b/react-yjs/vite.config.ts new file mode 100644 index 0000000000..c90997597d --- /dev/null +++ b/react-yjs/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], +}) diff --git a/solid-block-handle/.gitignore b/solid-block-handle/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-block-handle/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-block-handle/README.md b/solid-block-handle/README.md new file mode 100644 index 0000000000..83b6bbf0f8 --- /dev/null +++ b/solid-block-handle/README.md @@ -0,0 +1,15 @@ +# solid-block-handle + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-block-handle) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-block-handle) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-block-handle solid-block-handle +cd solid-block-handle +npm install +npm run dev +``` diff --git a/solid-block-handle/index.html b/solid-block-handle/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-block-handle/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-block-handle/package.json b/solid-block-handle/package.json new file mode 100644 index 0000000000..4c14b94cb2 --- /dev/null +++ b/solid-block-handle/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-block-handle", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-block-handle/src/App.tsx b/solid-block-handle/src/App.tsx new file mode 100644 index 0000000000..2cb5b6bb8d --- /dev/null +++ b/solid-block-handle/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/block-handle' + +export default function App() { + return +} diff --git a/solid-block-handle/src/app.css b/solid-block-handle/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-block-handle/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-block-handle/src/components/editor/examples/block-handle/editor.tsx b/solid-block-handle/src/components/editor/examples/block-handle/editor.tsx new file mode 100644 index 0000000000..f98ab63fdc --- /dev/null +++ b/solid-block-handle/src/components/editor/examples/block-handle/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-block-handle' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const extension = defineExtension() + const defaultContent = props.initialContent ?? sampleContent + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/solid-block-handle/src/components/editor/examples/block-handle/extension.ts b/solid-block-handle/src/components/editor/examples/block-handle/extension.ts new file mode 100644 index 0000000000..b5686b8c04 --- /dev/null +++ b/solid-block-handle/src/components/editor/examples/block-handle/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union(defineBasicExtension(), defineCodeBlockView()) +} + +export type EditorExtension = ReturnType diff --git a/solid-block-handle/src/components/editor/examples/block-handle/index.ts b/solid-block-handle/src/components/editor/examples/block-handle/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-block-handle/src/components/editor/examples/block-handle/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/solid-block-handle/src/components/editor/sample/sample-doc-block-handle.ts new file mode 100644 index 0000000000..3c6ccdc203 --- /dev/null +++ b/solid-block-handle/src/components/editor/sample/sample-doc-block-handle.ts @@ -0,0 +1,323 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Drag and Drop Demo', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Getting Started', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This paragraph can be moved above or below other blocks.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Different Block Types', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'You can drag paragraphs, headings, lists, code blocks, and more.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Lists Work Too', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This entire list can be dragged', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Individual list items stay together', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try moving this list around', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Ordered lists also support dragging', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The numbering updates automatically', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag this list to see it in action', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Even code blocks can be moved:', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: 'javascript', + }, + content: [ + { + type: 'text', + text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Nested Content', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This blockquote can be moved as a single unit.', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested blockquotes move together with their parent.', + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Try It Yourself', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Practice by moving this paragraph to the top of the document.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Or drag this one to between the headings above.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The drag handles make it easy to reorganize your content exactly how you want it.', + }, + ], + }, + ], +} diff --git a/solid-block-handle/src/components/editor/ui/block-handle/block-handle.tsx b/solid-block-handle/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..95e1693ef6 --- /dev/null +++ b/solid-block-handle/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,32 @@ +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/solid/block-handle' +import type { JSX } from 'solid-js' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props): JSX.Element { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/solid-block-handle/src/components/editor/ui/block-handle/index.ts b/solid-block-handle/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/solid-block-handle/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/solid-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx b/solid-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..2d67b563f7 --- /dev/null +++ b/solid-block-handle/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,36 @@ +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { SolidNodeViewProps } from 'prosekit/solid' +import { For, type JSX } from 'solid-js' + +export default function CodeBlockView(props: SolidNodeViewProps): JSX.Element { + const attrs = () => props.node.attrs as CodeBlockAttrs + const language = () => attrs().language + + const setLanguage = (lang: string) => { + const newAttrs: CodeBlockAttrs = { language: lang } + props.setAttrs(newAttrs) + } + + return ( + <> + +

+    
+  )
+}
diff --git a/solid-block-handle/src/components/editor/ui/code-block-view/index.ts b/solid-block-handle/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..50bbbea7df
--- /dev/null
+++ b/solid-block-handle/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSolidNodeView,
+  type SolidNodeViewComponent,
+} from 'prosekit/solid'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineSolidNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies SolidNodeViewComponent,
+  })
+}
diff --git a/solid-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/solid-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
new file mode 100644
index 0000000000..c5a24c7faa
--- /dev/null
+++ b/solid-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.tsx
@@ -0,0 +1,6 @@
+import { DropIndicator as BaseDropIndicator } from 'prosekit/solid/drop-indicator'
+import type { JSX } from 'solid-js'
+
+export default function DropIndicator(): JSX.Element {
+  return 
+}
diff --git a/solid-block-handle/src/components/editor/ui/drop-indicator/index.ts b/solid-block-handle/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..f8fb7139c4
--- /dev/null
+++ b/solid-block-handle/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator'
diff --git a/solid-block-handle/src/index.tsx b/solid-block-handle/src/index.tsx
new file mode 100644
index 0000000000..92b7740757
--- /dev/null
+++ b/solid-block-handle/src/index.tsx
@@ -0,0 +1,8 @@
+/* @refresh reload */
+import './app.css'
+import { render } from 'solid-js/web'
+import App from './App'
+
+const root = document.getElementById('root')
+
+render(() => , root!)
diff --git a/solid-block-handle/tsconfig.app.json b/solid-block-handle/tsconfig.app.json
new file mode 100644
index 0000000000..c0b480e758
--- /dev/null
+++ b/solid-block-handle/tsconfig.app.json
@@ -0,0 +1,29 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "target": "ES2022",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "types": ["vite/client"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+    "jsx": "preserve",
+    "jsxImportSource": "solid-js",
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["src"]
+}
diff --git a/solid-block-handle/tsconfig.json b/solid-block-handle/tsconfig.json
new file mode 100644
index 0000000000..1ffef600d9
--- /dev/null
+++ b/solid-block-handle/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "files": [],
+  "references": [
+    { "path": "./tsconfig.app.json" },
+    { "path": "./tsconfig.node.json" }
+  ]
+}
diff --git a/solid-block-handle/tsconfig.node.json b/solid-block-handle/tsconfig.node.json
new file mode 100644
index 0000000000..8a67f62f4c
--- /dev/null
+++ b/solid-block-handle/tsconfig.node.json
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "target": "ES2023",
+    "lib": ["ES2023"],
+    "module": "ESNext",
+    "types": ["node"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/solid-block-handle/vite.config.ts b/solid-block-handle/vite.config.ts
new file mode 100644
index 0000000000..9cb3cb51fd
--- /dev/null
+++ b/solid-block-handle/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import solid from 'vite-plugin-solid'
+import tailwindcss from '@tailwindcss/vite'
+
+export default defineConfig({
+  plugins: [solid(), tailwindcss()],
+})
diff --git a/solid-blockquote/.gitignore b/solid-blockquote/.gitignore
new file mode 100644
index 0000000000..5d6225c6df
--- /dev/null
+++ b/solid-blockquote/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+.next
+.svelte-kit
diff --git a/solid-blockquote/README.md b/solid-blockquote/README.md
new file mode 100644
index 0000000000..fcb3d7f858
--- /dev/null
+++ b/solid-blockquote/README.md
@@ -0,0 +1,15 @@
+# solid-blockquote
+
+A [ProseKit](https://prosekit.dev) example.
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-blockquote)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-blockquote)
+
+Run the example locally with:
+
+```bash
+npx degit prosekit/examples/solid-blockquote solid-blockquote
+cd solid-blockquote
+npm install
+npm run dev
+```
diff --git a/solid-blockquote/index.html b/solid-blockquote/index.html
new file mode 100644
index 0000000000..375ea8dbc4
--- /dev/null
+++ b/solid-blockquote/index.html
@@ -0,0 +1,12 @@
+
+
+  
+    
+    
+    ProseKit + Solid
+  
+  
+    
+ + + diff --git a/solid-blockquote/package.json b/solid-blockquote/package.json new file mode 100644 index 0000000000..6018436295 --- /dev/null +++ b/solid-blockquote/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-blockquote", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-blockquote/src/App.tsx b/solid-blockquote/src/App.tsx new file mode 100644 index 0000000000..3327cfcf2d --- /dev/null +++ b/solid-blockquote/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/blockquote' + +export default function App() { + return +} diff --git a/solid-blockquote/src/app.css b/solid-blockquote/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-blockquote/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-blockquote/src/components/editor/examples/blockquote/editor.tsx b/solid-blockquote/src/components/editor/examples/blockquote/editor.tsx new file mode 100644 index 0000000000..05c47ad54e --- /dev/null +++ b/solid-blockquote/src/components/editor/examples/blockquote/editor.tsx @@ -0,0 +1,29 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-blockquote/src/components/editor/examples/blockquote/extension.ts b/solid-blockquote/src/components/editor/examples/blockquote/extension.ts new file mode 100644 index 0000000000..5292b59e35 --- /dev/null +++ b/solid-blockquote/src/components/editor/examples/blockquote/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBlockquote(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-blockquote/src/components/editor/examples/blockquote/index.ts b/solid-blockquote/src/components/editor/examples/blockquote/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-blockquote/src/components/editor/examples/blockquote/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-blockquote/src/components/editor/ui/button/button.tsx b/solid-blockquote/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-blockquote/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-blockquote/src/components/editor/ui/button/index.ts b/solid-blockquote/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-blockquote/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/solid-blockquote/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-blockquote/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-blockquote/src/components/editor/ui/toolbar/index.ts b/solid-blockquote/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-blockquote/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-blockquote/src/components/editor/ui/toolbar/toolbar.tsx b/solid-blockquote/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-blockquote/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-blockquote/src/index.tsx b/solid-blockquote/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-blockquote/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-blockquote/tsconfig.app.json b/solid-blockquote/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-blockquote/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-blockquote/tsconfig.json b/solid-blockquote/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-blockquote/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-blockquote/tsconfig.node.json b/solid-blockquote/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-blockquote/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-blockquote/vite.config.ts b/solid-blockquote/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-blockquote/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-bold/.gitignore b/solid-bold/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-bold/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-bold/README.md b/solid-bold/README.md new file mode 100644 index 0000000000..b089887930 --- /dev/null +++ b/solid-bold/README.md @@ -0,0 +1,15 @@ +# solid-bold + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-bold) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-bold) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-bold solid-bold +cd solid-bold +npm install +npm run dev +``` diff --git a/solid-bold/index.html b/solid-bold/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-bold/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-bold/package.json b/solid-bold/package.json new file mode 100644 index 0000000000..753ecdd5b9 --- /dev/null +++ b/solid-bold/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-bold", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-bold/src/App.tsx b/solid-bold/src/App.tsx new file mode 100644 index 0000000000..274955047d --- /dev/null +++ b/solid-bold/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/bold' + +export default function App() { + return +} diff --git a/solid-bold/src/app.css b/solid-bold/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-bold/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-bold/src/components/editor/examples/bold/editor.tsx b/solid-bold/src/components/editor/examples/bold/editor.tsx new file mode 100644 index 0000000000..b0fb2216a5 --- /dev/null +++ b/solid-bold/src/components/editor/examples/bold/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-bold' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-bold/src/components/editor/examples/bold/extension.ts b/solid-bold/src/components/editor/examples/bold/extension.ts new file mode 100644 index 0000000000..eaa4fba721 --- /dev/null +++ b/solid-bold/src/components/editor/examples/bold/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBold } from 'prosekit/extensions/bold' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBold(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-bold/src/components/editor/examples/bold/index.ts b/solid-bold/src/components/editor/examples/bold/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-bold/src/components/editor/examples/bold/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-bold/src/components/editor/sample/sample-doc-bold.ts b/solid-bold/src/components/editor/sample/sample-doc-bold.ts new file mode 100644 index 0000000000..09ed08daad --- /dev/null +++ b/solid-bold/src/components/editor/sample/sample-doc-bold.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/solid-bold/src/components/editor/ui/button/button.tsx b/solid-bold/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-bold/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-bold/src/components/editor/ui/button/index.ts b/solid-bold/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-bold/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-bold/src/components/editor/ui/image-upload-popover/index.ts b/solid-bold/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-bold/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-bold/src/components/editor/ui/toolbar/index.ts b/solid-bold/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-bold/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-bold/src/components/editor/ui/toolbar/toolbar.tsx b/solid-bold/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-bold/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-bold/src/index.tsx b/solid-bold/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-bold/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-bold/tsconfig.app.json b/solid-bold/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-bold/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-bold/tsconfig.json b/solid-bold/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-bold/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-bold/tsconfig.node.json b/solid-bold/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-bold/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-bold/vite.config.ts b/solid-bold/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-bold/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-change-tracking/.gitignore b/solid-change-tracking/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-change-tracking/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-change-tracking/README.md b/solid-change-tracking/README.md new file mode 100644 index 0000000000..1a4f29381a --- /dev/null +++ b/solid-change-tracking/README.md @@ -0,0 +1,15 @@ +# solid-change-tracking + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-change-tracking) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-change-tracking) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-change-tracking solid-change-tracking +cd solid-change-tracking +npm install +npm run dev +``` diff --git a/solid-change-tracking/index.html b/solid-change-tracking/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-change-tracking/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-change-tracking/package.json b/solid-change-tracking/package.json new file mode 100644 index 0000000000..bad9b72c6e --- /dev/null +++ b/solid-change-tracking/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-change-tracking", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-change-tracking/src/App.tsx b/solid-change-tracking/src/App.tsx new file mode 100644 index 0000000000..88160e69c9 --- /dev/null +++ b/solid-change-tracking/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/change-tracking' + +export default function App() { + return +} diff --git a/solid-change-tracking/src/app.css b/solid-change-tracking/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-change-tracking/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx b/solid-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx new file mode 100644 index 0000000000..0d95a96575 --- /dev/null +++ b/solid-change-tracking/src/components/editor/examples/change-tracking/editor-diff.tsx @@ -0,0 +1,28 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, union } from 'prosekit/core' +import { defineCommitViewer, type Commit } from 'prosekit/extensions/commit' +import { defineReadonly } from 'prosekit/extensions/readonly' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +export default function EditorDiff(props: { commit: Commit }): JSX.Element { + const extension = union( + defineBasicExtension(), + defineReadonly(), + defineCommitViewer(props.commit), + ) + const editor = createEditor({ extension }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx b/solid-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx new file mode 100644 index 0000000000..d05b604134 --- /dev/null +++ b/solid-change-tracking/src/components/editor/examples/change-tracking/editor-main.tsx @@ -0,0 +1,38 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, union, type NodeJSON } from 'prosekit/core' +import { + defineCommitRecorder, + type CommitRecorder, +} from 'prosekit/extensions/commit' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +export default function EditorMain(props: { + commitRecorder: CommitRecorder + initialContent?: NodeJSON +}): JSX.Element { + const extension = union( + defineBasicExtension(), + defineCommitRecorder(props.commitRecorder), + ) + const editor = createEditor({ + extension, + defaultContent: props.initialContent, + }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-change-tracking/src/components/editor/examples/change-tracking/editor.tsx b/solid-change-tracking/src/components/editor/examples/change-tracking/editor.tsx new file mode 100644 index 0000000000..7a890490ef --- /dev/null +++ b/solid-change-tracking/src/components/editor/examples/change-tracking/editor.tsx @@ -0,0 +1,82 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import type { NodeJSON } from 'prosekit/core' +import { CommitRecorder, type Commit } from 'prosekit/extensions/commit' +import { createSignal, For, type JSX } from 'solid-js' + +import EditorDiff from './editor-diff' +import EditorMain from './editor-main' + +export default function Editor(): JSX.Element { + const [commits, setCommits] = createSignal< + { id: string; date: Date; commit: Commit }[] + >([]) + const [key, setKey] = createSignal(0) + const [initialContent, setInitialContent] = createSignal< + NodeJSON | undefined + >() + const commitRecorder = new CommitRecorder() + + const handleCommit = () => { + const commit = commitRecorder.commit() + if (!commit) return + const id = Math.random().toString(36).slice(2, 9) + setCommits((commits) => [{ id, date: new Date(), commit }, ...commits]) + } + + const handleRestore = (id: string) => { + const commitIndex = commits().findIndex((commit) => commit.id === id) + const commit = commits()[commitIndex] + if (commitIndex === -1 || !commit) return + const doc = commit.commit.doc + setInitialContent(doc) + setCommits((commits) => commits.slice(commitIndex)) + setKey((key) => key + 1) + } + + return ( +
+
+
+ + {() => ( + + )} + +
+ +
+
+ + {(commit) => ( +
+
+ +
+
+ + {commit.date.toLocaleTimeString()} + + +
+
+ )} +
+
+
+ ) +} diff --git a/solid-change-tracking/src/components/editor/examples/change-tracking/index.ts b/solid-change-tracking/src/components/editor/examples/change-tracking/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-change-tracking/src/components/editor/examples/change-tracking/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-change-tracking/src/index.tsx b/solid-change-tracking/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-change-tracking/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-change-tracking/tsconfig.app.json b/solid-change-tracking/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-change-tracking/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-change-tracking/tsconfig.json b/solid-change-tracking/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-change-tracking/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-change-tracking/tsconfig.node.json b/solid-change-tracking/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-change-tracking/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-change-tracking/vite.config.ts b/solid-change-tracking/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-change-tracking/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-code-block-themes/.gitignore b/solid-code-block-themes/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-code-block-themes/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-code-block-themes/README.md b/solid-code-block-themes/README.md new file mode 100644 index 0000000000..d14681c4c5 --- /dev/null +++ b/solid-code-block-themes/README.md @@ -0,0 +1,15 @@ +# solid-code-block-themes + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-code-block-themes) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-code-block-themes) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-code-block-themes solid-code-block-themes +cd solid-code-block-themes +npm install +npm run dev +``` diff --git a/solid-code-block-themes/index.html b/solid-code-block-themes/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-code-block-themes/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-code-block-themes/package.json b/solid-code-block-themes/package.json new file mode 100644 index 0000000000..797e359d7c --- /dev/null +++ b/solid-code-block-themes/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-code-block-themes", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-code-block-themes/src/App.tsx b/solid-code-block-themes/src/App.tsx new file mode 100644 index 0000000000..9b93464b4e --- /dev/null +++ b/solid-code-block-themes/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code-block-themes' + +export default function App() { + return +} diff --git a/solid-code-block-themes/src/app.css b/solid-code-block-themes/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-code-block-themes/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx b/solid-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx new file mode 100644 index 0000000000..efa2dcbb51 --- /dev/null +++ b/solid-code-block-themes/src/components/editor/examples/code-block-themes/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-code-block' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/solid-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts new file mode 100644 index 0000000000..b5686b8c04 --- /dev/null +++ b/solid-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union(defineBasicExtension(), defineCodeBlockView()) +} + +export type EditorExtension = ReturnType diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/solid-code-block-themes/src/components/editor/examples/code-block-themes/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-code-block-themes/src/components/editor/examples/code-block-themes/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx b/solid-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx new file mode 100644 index 0000000000..63188073ca --- /dev/null +++ b/solid-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.tsx @@ -0,0 +1,31 @@ +import { + defineCodeBlockShiki, + shikiBundledThemesInfo, + type ShikiBundledTheme, +} from 'prosekit/extensions/code-block' +import { useExtension } from 'prosekit/solid' +import { createMemo, createSignal, For, type JSX } from 'solid-js' + +export function ThemeSelector(): JSX.Element { + const [theme, setTheme] = createSignal('github-dark') + const extension = createMemo(() => { + return defineCodeBlockShiki({ themes: [theme() as ShikiBundledTheme] }) + }) + useExtension(extension) + + return ( + <> + + + + ) +} diff --git a/solid-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx b/solid-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx new file mode 100644 index 0000000000..7fc735f1d1 --- /dev/null +++ b/solid-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.tsx @@ -0,0 +1,11 @@ +import type { JSX } from 'solid-js' + +import { ThemeSelector } from './theme-selector' + +export default function Toolbar(): JSX.Element { + return ( +
+ +
+ ) +} diff --git a/solid-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/solid-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/solid-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/solid-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx b/solid-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..2d67b563f7 --- /dev/null +++ b/solid-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,36 @@ +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { SolidNodeViewProps } from 'prosekit/solid' +import { For, type JSX } from 'solid-js' + +export default function CodeBlockView(props: SolidNodeViewProps): JSX.Element { + const attrs = () => props.node.attrs as CodeBlockAttrs + const language = () => attrs().language + + const setLanguage = (lang: string) => { + const newAttrs: CodeBlockAttrs = { language: lang } + props.setAttrs(newAttrs) + } + + return ( + <> + +

+    
+  )
+}
diff --git a/solid-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/solid-code-block-themes/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..50bbbea7df
--- /dev/null
+++ b/solid-code-block-themes/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSolidNodeView,
+  type SolidNodeViewComponent,
+} from 'prosekit/solid'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineSolidNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies SolidNodeViewComponent,
+  })
+}
diff --git a/solid-code-block-themes/src/index.tsx b/solid-code-block-themes/src/index.tsx
new file mode 100644
index 0000000000..92b7740757
--- /dev/null
+++ b/solid-code-block-themes/src/index.tsx
@@ -0,0 +1,8 @@
+/* @refresh reload */
+import './app.css'
+import { render } from 'solid-js/web'
+import App from './App'
+
+const root = document.getElementById('root')
+
+render(() => , root!)
diff --git a/solid-code-block-themes/tsconfig.app.json b/solid-code-block-themes/tsconfig.app.json
new file mode 100644
index 0000000000..c0b480e758
--- /dev/null
+++ b/solid-code-block-themes/tsconfig.app.json
@@ -0,0 +1,29 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+    "target": "ES2022",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "types": ["vite/client"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+    "jsx": "preserve",
+    "jsxImportSource": "solid-js",
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["src"]
+}
diff --git a/solid-code-block-themes/tsconfig.json b/solid-code-block-themes/tsconfig.json
new file mode 100644
index 0000000000..1ffef600d9
--- /dev/null
+++ b/solid-code-block-themes/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "files": [],
+  "references": [
+    { "path": "./tsconfig.app.json" },
+    { "path": "./tsconfig.node.json" }
+  ]
+}
diff --git a/solid-code-block-themes/tsconfig.node.json b/solid-code-block-themes/tsconfig.node.json
new file mode 100644
index 0000000000..8a67f62f4c
--- /dev/null
+++ b/solid-code-block-themes/tsconfig.node.json
@@ -0,0 +1,26 @@
+{
+  "compilerOptions": {
+    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+    "target": "ES2023",
+    "lib": ["ES2023"],
+    "module": "ESNext",
+    "types": ["node"],
+    "skipLibCheck": true,
+
+    /* Bundler mode */
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "verbatimModuleSyntax": true,
+    "moduleDetection": "force",
+    "noEmit": true,
+
+    /* Linting */
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "erasableSyntaxOnly": true,
+    "noFallthroughCasesInSwitch": true,
+    "noUncheckedSideEffectImports": true
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/solid-code-block-themes/vite.config.ts b/solid-code-block-themes/vite.config.ts
new file mode 100644
index 0000000000..9cb3cb51fd
--- /dev/null
+++ b/solid-code-block-themes/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vite'
+import solid from 'vite-plugin-solid'
+import tailwindcss from '@tailwindcss/vite'
+
+export default defineConfig({
+  plugins: [solid(), tailwindcss()],
+})
diff --git a/solid-code-block/.gitignore b/solid-code-block/.gitignore
new file mode 100644
index 0000000000..5d6225c6df
--- /dev/null
+++ b/solid-code-block/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+.next
+.svelte-kit
diff --git a/solid-code-block/README.md b/solid-code-block/README.md
new file mode 100644
index 0000000000..afa9c05889
--- /dev/null
+++ b/solid-code-block/README.md
@@ -0,0 +1,15 @@
+# solid-code-block
+
+A [ProseKit](https://prosekit.dev) example.
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-code-block)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-code-block)
+
+Run the example locally with:
+
+```bash
+npx degit prosekit/examples/solid-code-block solid-code-block
+cd solid-code-block
+npm install
+npm run dev
+```
diff --git a/solid-code-block/index.html b/solid-code-block/index.html
new file mode 100644
index 0000000000..375ea8dbc4
--- /dev/null
+++ b/solid-code-block/index.html
@@ -0,0 +1,12 @@
+
+
+  
+    
+    
+    ProseKit + Solid
+  
+  
+    
+ + + diff --git a/solid-code-block/package.json b/solid-code-block/package.json new file mode 100644 index 0000000000..a2ab09f621 --- /dev/null +++ b/solid-code-block/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-code-block", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-code-block/src/App.tsx b/solid-code-block/src/App.tsx new file mode 100644 index 0000000000..961ce70aad --- /dev/null +++ b/solid-code-block/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code-block' + +export default function App() { + return +} diff --git a/solid-code-block/src/app.css b/solid-code-block/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-code-block/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-code-block/src/components/editor/examples/code-block/editor.tsx b/solid-code-block/src/components/editor/examples/code-block/editor.tsx new file mode 100644 index 0000000000..b989b65867 --- /dev/null +++ b/solid-code-block/src/components/editor/examples/code-block/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-code-block' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-code-block/src/components/editor/examples/code-block/extension.ts b/solid-code-block/src/components/editor/examples/code-block/extension.ts new file mode 100644 index 0000000000..099cacf03b --- /dev/null +++ b/solid-code-block/src/components/editor/examples/code-block/extension.ts @@ -0,0 +1,24 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { + defineCodeBlock, + defineCodeBlockShiki, +} from 'prosekit/extensions/code-block' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCodeBlock(), + defineCodeBlockShiki(), + defineCodeBlockView(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-code-block/src/components/editor/examples/code-block/index.ts b/solid-code-block/src/components/editor/examples/code-block/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-code-block/src/components/editor/examples/code-block/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-code-block/src/components/editor/sample/sample-doc-code-block.ts b/solid-code-block/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/solid-code-block/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/solid-code-block/src/components/editor/ui/button/button.tsx b/solid-code-block/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-code-block/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-code-block/src/components/editor/ui/button/index.ts b/solid-code-block/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-code-block/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx b/solid-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..2d67b563f7 --- /dev/null +++ b/solid-code-block/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,36 @@ +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { SolidNodeViewProps } from 'prosekit/solid' +import { For, type JSX } from 'solid-js' + +export default function CodeBlockView(props: SolidNodeViewProps): JSX.Element { + const attrs = () => props.node.attrs as CodeBlockAttrs + const language = () => attrs().language + + const setLanguage = (lang: string) => { + const newAttrs: CodeBlockAttrs = { language: lang } + props.setAttrs(newAttrs) + } + + return ( + <> + +

+    
+  )
+}
diff --git a/solid-code-block/src/components/editor/ui/code-block-view/index.ts b/solid-code-block/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..50bbbea7df
--- /dev/null
+++ b/solid-code-block/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSolidNodeView,
+  type SolidNodeViewComponent,
+} from 'prosekit/solid'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineSolidNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies SolidNodeViewComponent,
+  })
+}
diff --git a/solid-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
new file mode 100644
index 0000000000..efa306305f
--- /dev/null
+++ b/solid-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
@@ -0,0 +1,137 @@
+import type { Uploader } from 'prosekit/extensions/file'
+import type { ImageExtension } from 'prosekit/extensions/image'
+import { useEditor } from 'prosekit/solid'
+import {
+  PopoverPopup,
+  PopoverPositioner,
+  PopoverRoot,
+  PopoverTrigger,
+} from 'prosekit/solid/popover'
+import type { OpenChangeEvent } from 'prosekit/web/popover'
+import { createSignal, createUniqueId, Show, type JSX } from 'solid-js'
+
+import { Button } from '../button'
+
+export default function ImageUploadPopover(props: {
+  uploader: Uploader
+  tooltip: string
+  disabled: boolean
+  children: JSX.Element
+}): JSX.Element {
+  const [open, setOpen] = createSignal(false)
+  const [url, setUrl] = createSignal('')
+  const [file, setFile] = createSignal(null)
+  const ariaId = createUniqueId()
+
+  const editor = useEditor()
+
+  const handleFileChange = (event: Event) => {
+    const target = event.target as HTMLInputElement
+    const selectedFile = target.files?.[0]
+
+    if (selectedFile) {
+      setFile(selectedFile)
+      setUrl('')
+    } else {
+      setFile(null)
+    }
+  }
+
+  const handleUrlChange = (event: Event) => {
+    const target = event.target as HTMLInputElement
+    const inputUrl = target.value
+
+    if (inputUrl) {
+      setUrl(inputUrl)
+      setFile(null)
+    } else {
+      setUrl('')
+    }
+  }
+
+  const deferResetState = () => {
+    setTimeout(() => {
+      setUrl('')
+      setFile(null)
+    }, 300)
+  }
+
+  const handleSubmit = () => {
+    if (url()) {
+      editor().commands.insertImage({ src: url() })
+    } else if (file()) {
+      editor().commands.uploadImage({ file: file()!, uploader: props.uploader })
+    }
+    setOpen(false)
+    deferResetState()
+  }
+
+  const handleOpenChange = (event: OpenChangeEvent) => {
+    if (!event.detail) {
+      deferResetState()
+    }
+    setOpen(event.detail)
+  }
+
+  return (
+    
+      
+        
+      
+
+      
+        
+          
+            
+            
+          
+
+          
+            
+            
+          
+
+          
+            
+          
+
+          
+            
+          
+        
+      
+    
+  )
+}
diff --git a/solid-code-block/src/components/editor/ui/image-upload-popover/index.ts b/solid-code-block/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..5d49d873ce
--- /dev/null
+++ b/solid-code-block/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/solid-code-block/src/components/editor/ui/toolbar/index.ts b/solid-code-block/src/components/editor/ui/toolbar/index.ts
new file mode 100644
index 0000000000..fdf6741e6a
--- /dev/null
+++ b/solid-code-block/src/components/editor/ui/toolbar/index.ts
@@ -0,0 +1 @@
+export { default as Toolbar } from './toolbar'
diff --git a/solid-code-block/src/components/editor/ui/toolbar/toolbar.tsx b/solid-code-block/src/components/editor/ui/toolbar/toolbar.tsx
new file mode 100644
index 0000000000..ee3858791a
--- /dev/null
+++ b/solid-code-block/src/components/editor/ui/toolbar/toolbar.tsx
@@ -0,0 +1,406 @@
+import type { BasicExtension } from 'prosekit/basic'
+import type { Editor } from 'prosekit/core'
+import type { Uploader } from 'prosekit/extensions/file'
+import { useEditorDerivedValue } from 'prosekit/solid'
+import { Show, type JSX } from 'solid-js'
+
+import { Button } from '../button'
+import { ImageUploadPopover } from '../image-upload-popover'
+
+function getToolbarItems(editor: Editor) {
+  return {
+    undo: editor.commands.undo
+      ? {
+          isActive: false,
+          canExec: editor.commands.undo.canExec(),
+          command: () => editor.commands.undo(),
+        }
+      : undefined,
+    redo: editor.commands.redo
+      ? {
+          isActive: false,
+          canExec: editor.commands.redo.canExec(),
+          command: () => editor.commands.redo(),
+        }
+      : undefined,
+    bold: editor.commands.toggleBold
+      ? {
+          isActive: editor.marks.bold.isActive(),
+          canExec: editor.commands.toggleBold.canExec(),
+          command: () => editor.commands.toggleBold(),
+        }
+      : undefined,
+    italic: editor.commands.toggleItalic
+      ? {
+          isActive: editor.marks.italic.isActive(),
+          canExec: editor.commands.toggleItalic.canExec(),
+          command: () => editor.commands.toggleItalic(),
+        }
+      : undefined,
+    underline: editor.commands.toggleUnderline
+      ? {
+          isActive: editor.marks.underline.isActive(),
+          canExec: editor.commands.toggleUnderline.canExec(),
+          command: () => editor.commands.toggleUnderline(),
+        }
+      : undefined,
+    strike: editor.commands.toggleStrike
+      ? {
+          isActive: editor.marks.strike.isActive(),
+          canExec: editor.commands.toggleStrike.canExec(),
+          command: () => editor.commands.toggleStrike(),
+        }
+      : undefined,
+    code: editor.commands.toggleCode
+      ? {
+          isActive: editor.marks.code.isActive(),
+          canExec: editor.commands.toggleCode.canExec(),
+          command: () => editor.commands.toggleCode(),
+        }
+      : undefined,
+    codeBlock: editor.commands.insertCodeBlock
+      ? {
+          isActive: editor.nodes.codeBlock.isActive(),
+          canExec: editor.commands.insertCodeBlock.canExec({
+            language: 'javascript',
+          }),
+          command: () =>
+            editor.commands.insertCodeBlock({ language: 'javascript' }),
+        }
+      : undefined,
+    heading1: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 1 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 1 }),
+          command: () => editor.commands.toggleHeading({ level: 1 }),
+        }
+      : undefined,
+    heading2: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 2 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 2 }),
+          command: () => editor.commands.toggleHeading({ level: 2 }),
+        }
+      : undefined,
+    heading3: editor.commands.toggleHeading
+      ? {
+          isActive: editor.nodes.heading.isActive({ level: 3 }),
+          canExec: editor.commands.toggleHeading.canExec({ level: 3 }),
+          command: () => editor.commands.toggleHeading({ level: 3 }),
+        }
+      : undefined,
+    horizontalRule: editor.commands.insertHorizontalRule
+      ? {
+          isActive: editor.nodes.horizontalRule.isActive(),
+          canExec: editor.commands.insertHorizontalRule.canExec(),
+          command: () => editor.commands.insertHorizontalRule(),
+        }
+      : undefined,
+    blockquote: editor.commands.toggleBlockquote
+      ? {
+          isActive: editor.nodes.blockquote.isActive(),
+          canExec: editor.commands.toggleBlockquote.canExec(),
+          command: () => editor.commands.toggleBlockquote(),
+        }
+      : undefined,
+    bulletList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'bullet' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }),
+          command: () => editor.commands.toggleList({ kind: 'bullet' }),
+        }
+      : undefined,
+    orderedList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'ordered' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }),
+          command: () => editor.commands.toggleList({ kind: 'ordered' }),
+        }
+      : undefined,
+    taskList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'task' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'task' }),
+          command: () => editor.commands.toggleList({ kind: 'task' }),
+        }
+      : undefined,
+    toggleList: editor.commands.toggleList
+      ? {
+          isActive: editor.nodes.list.isActive({ kind: 'toggle' }),
+          canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }),
+          command: () => editor.commands.toggleList({ kind: 'toggle' }),
+        }
+      : undefined,
+    indentList: editor.commands.indentList
+      ? {
+          isActive: false,
+          canExec: editor.commands.indentList.canExec(),
+          command: () => editor.commands.indentList(),
+        }
+      : undefined,
+    dedentList: editor.commands.dedentList
+      ? {
+          isActive: false,
+          canExec: editor.commands.dedentList.canExec(),
+          command: () => editor.commands.dedentList(),
+        }
+      : undefined,
+    insertImage: editor.commands.insertImage
+      ? {
+          isActive: false,
+          canExec: editor.commands.insertImage.canExec(),
+        }
+      : undefined,
+  }
+}
+
+export default function Toolbar(props: {
+  uploader?: Uploader
+}): JSX.Element {
+  const items = useEditorDerivedValue(getToolbarItems)
+
+  return (
+    
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-code-block/src/index.tsx b/solid-code-block/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-code-block/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-code-block/tsconfig.app.json b/solid-code-block/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-code-block/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-code-block/tsconfig.json b/solid-code-block/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-code-block/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-code-block/tsconfig.node.json b/solid-code-block/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-code-block/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-code-block/vite.config.ts b/solid-code-block/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-code-block/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-code/.gitignore b/solid-code/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-code/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-code/README.md b/solid-code/README.md new file mode 100644 index 0000000000..39c8ebbc11 --- /dev/null +++ b/solid-code/README.md @@ -0,0 +1,15 @@ +# solid-code + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-code) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-code) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-code solid-code +cd solid-code +npm install +npm run dev +``` diff --git a/solid-code/index.html b/solid-code/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-code/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-code/package.json b/solid-code/package.json new file mode 100644 index 0000000000..248c1274f4 --- /dev/null +++ b/solid-code/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-code", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-code/src/App.tsx b/solid-code/src/App.tsx new file mode 100644 index 0000000000..f2f5d9a360 --- /dev/null +++ b/solid-code/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/code' + +export default function App() { + return +} diff --git a/solid-code/src/app.css b/solid-code/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-code/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-code/src/components/editor/examples/code/editor.tsx b/solid-code/src/components/editor/examples/code/editor.tsx new file mode 100644 index 0000000000..664f3bb7ee --- /dev/null +++ b/solid-code/src/components/editor/examples/code/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-code' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-code/src/components/editor/examples/code/extension.ts b/solid-code/src/components/editor/examples/code/extension.ts new file mode 100644 index 0000000000..e9e273216e --- /dev/null +++ b/solid-code/src/components/editor/examples/code/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCode(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-code/src/components/editor/examples/code/index.ts b/solid-code/src/components/editor/examples/code/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-code/src/components/editor/examples/code/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-code/src/components/editor/sample/sample-doc-code.ts b/solid-code/src/components/editor/sample/sample-doc-code.ts new file mode 100644 index 0000000000..2fdbcee1f3 --- /dev/null +++ b/solid-code/src/components/editor/sample/sample-doc-code.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'This is code', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/solid-code/src/components/editor/ui/button/button.tsx b/solid-code/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-code/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-code/src/components/editor/ui/button/index.ts b/solid-code/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-code/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-code/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-code/src/components/editor/ui/image-upload-popover/index.ts b/solid-code/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-code/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-code/src/components/editor/ui/toolbar/index.ts b/solid-code/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-code/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-code/src/components/editor/ui/toolbar/toolbar.tsx b/solid-code/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-code/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-code/src/index.tsx b/solid-code/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-code/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-code/tsconfig.app.json b/solid-code/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-code/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-code/tsconfig.json b/solid-code/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-code/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-code/tsconfig.node.json b/solid-code/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-code/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-code/vite.config.ts b/solid-code/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-code/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-drop-cursor/.gitignore b/solid-drop-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-drop-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-drop-cursor/README.md b/solid-drop-cursor/README.md new file mode 100644 index 0000000000..747d97ef31 --- /dev/null +++ b/solid-drop-cursor/README.md @@ -0,0 +1,15 @@ +# solid-drop-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-drop-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-drop-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-drop-cursor solid-drop-cursor +cd solid-drop-cursor +npm install +npm run dev +``` diff --git a/solid-drop-cursor/index.html b/solid-drop-cursor/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-drop-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-drop-cursor/package.json b/solid-drop-cursor/package.json new file mode 100644 index 0000000000..b362ad4e72 --- /dev/null +++ b/solid-drop-cursor/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-drop-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-drop-cursor/src/App.tsx b/solid-drop-cursor/src/App.tsx new file mode 100644 index 0000000000..f66459b286 --- /dev/null +++ b/solid-drop-cursor/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/drop-cursor' + +export default function App() { + return +} diff --git a/solid-drop-cursor/src/app.css b/solid-drop-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-drop-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx b/solid-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx new file mode 100644 index 0000000000..efcf2d16b5 --- /dev/null +++ b/solid-drop-cursor/src/components/editor/examples/drop-cursor/editor.tsx @@ -0,0 +1,33 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-drop-cursor' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/solid-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts new file mode 100644 index 0000000000..fd79a2c96c --- /dev/null +++ b/solid-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts @@ -0,0 +1,23 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineImage(), + defineDropCursor({ + color: false, + width: 4, + class: 'transition-all bg-blue-500', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/solid-drop-cursor/src/components/editor/examples/drop-cursor/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-drop-cursor/src/components/editor/examples/drop-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/solid-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts new file mode 100644 index 0000000000..22c6b93465 --- /dev/null +++ b/solid-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts @@ -0,0 +1,40 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the images below to see the custom drop cursor.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/320x240/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/green/320x240/40', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blue/320x240/187', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/red/320x240/188', + }, + }, + ], +} diff --git a/solid-drop-cursor/src/index.tsx b/solid-drop-cursor/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-drop-cursor/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-drop-cursor/tsconfig.app.json b/solid-drop-cursor/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-drop-cursor/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-drop-cursor/tsconfig.json b/solid-drop-cursor/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-drop-cursor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-drop-cursor/tsconfig.node.json b/solid-drop-cursor/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-drop-cursor/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-drop-cursor/vite.config.ts b/solid-drop-cursor/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-drop-cursor/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-emoji-rules/.gitignore b/solid-emoji-rules/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-emoji-rules/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-emoji-rules/README.md b/solid-emoji-rules/README.md new file mode 100644 index 0000000000..6c7a5fdda3 --- /dev/null +++ b/solid-emoji-rules/README.md @@ -0,0 +1,15 @@ +# solid-emoji-rules + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-emoji-rules) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-emoji-rules) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-emoji-rules solid-emoji-rules +cd solid-emoji-rules +npm install +npm run dev +``` diff --git a/solid-emoji-rules/index.html b/solid-emoji-rules/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-emoji-rules/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-emoji-rules/package.json b/solid-emoji-rules/package.json new file mode 100644 index 0000000000..b780036fa9 --- /dev/null +++ b/solid-emoji-rules/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-emoji-rules", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-emoji-rules/src/App.tsx b/solid-emoji-rules/src/App.tsx new file mode 100644 index 0000000000..1e4ef54fd6 --- /dev/null +++ b/solid-emoji-rules/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/emoji-rules' + +export default function App() { + return +} diff --git a/solid-emoji-rules/src/app.css b/solid-emoji-rules/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-emoji-rules/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx b/solid-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx new file mode 100644 index 0000000000..6f695978e8 --- /dev/null +++ b/solid-emoji-rules/src/components/editor/examples/emoji-rules/editor.tsx @@ -0,0 +1,26 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { defineExtension } from './extension' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/solid-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts new file mode 100644 index 0000000000..5cac9cbc79 --- /dev/null +++ b/solid-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts @@ -0,0 +1,15 @@ +import { defineEnterRule } from 'prosekit/extensions/enter-rule' + +/** + * Converts the text before the text cursor into an emoji when pressing `Enter`. + */ +export function defineEmojiEnterRule() { + return defineEnterRule({ + regex: /:(apple|banana):$/, + handler: ({ match, from, to, state }) => { + const text = match[1] as 'apple' | 'banana' + const emoji = text === 'apple' ? '🍎' : '🍌' + return state.tr.replaceWith(from, to, state.schema.text(emoji)) + }, + }) +} diff --git a/solid-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/solid-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts new file mode 100644 index 0000000000..bc9bcb8412 --- /dev/null +++ b/solid-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts @@ -0,0 +1,15 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { defineEmojiEnterRule } from './emoji' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineEmojiEnterRule(), + definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/solid-emoji-rules/src/components/editor/examples/emoji-rules/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-emoji-rules/src/components/editor/examples/emoji-rules/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-emoji-rules/src/index.tsx b/solid-emoji-rules/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-emoji-rules/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-emoji-rules/tsconfig.app.json b/solid-emoji-rules/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-emoji-rules/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-emoji-rules/tsconfig.json b/solid-emoji-rules/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-emoji-rules/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-emoji-rules/tsconfig.node.json b/solid-emoji-rules/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-emoji-rules/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-emoji-rules/vite.config.ts b/solid-emoji-rules/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-emoji-rules/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-full/.gitignore b/solid-full/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-full/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-full/README.md b/solid-full/README.md new file mode 100644 index 0000000000..063b56d28a --- /dev/null +++ b/solid-full/README.md @@ -0,0 +1,15 @@ +# solid-full + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-full) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-full) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-full solid-full +cd solid-full +npm install +npm run dev +``` diff --git a/solid-full/index.html b/solid-full/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-full/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-full/package.json b/solid-full/package.json new file mode 100644 index 0000000000..4b332173d3 --- /dev/null +++ b/solid-full/package.json @@ -0,0 +1,26 @@ +{ + "name": "example-solid-full", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-full/src/App.tsx b/solid-full/src/App.tsx new file mode 100644 index 0000000000..c93bd3a429 --- /dev/null +++ b/solid-full/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/full' + +export default function App() { + return +} diff --git a/solid-full/src/app.css b/solid-full/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-full/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-full/src/components/editor/examples/full/editor.tsx b/solid-full/src/components/editor/examples/full/editor.tsx new file mode 100644 index 0000000000..8f158cfa67 --- /dev/null +++ b/solid-full/src/components/editor/examples/full/editor.tsx @@ -0,0 +1,52 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-full' +import { tags } from '../../sample/sample-tag-data' +import { sampleUploader } from '../../sample/sample-uploader' +import { users } from '../../sample/sample-user-data' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' +import { InlineMenu } from '../../ui/inline-menu' +import { SlashMenu } from '../../ui/slash-menu' +import { TableHandle } from '../../ui/table-handle' +import { TagMenu } from '../../ui/tag-menu' +import { Toolbar } from '../../ui/toolbar' +import { UserMenu } from '../../ui/user-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+ + + + + + + +
+
+
+ ) +} diff --git a/solid-full/src/components/editor/examples/full/extension.ts b/solid-full/src/components/editor/examples/full/extension.ts new file mode 100644 index 0000000000..5fc2f60685 --- /dev/null +++ b/solid-full/src/components/editor/examples/full/extension.ts @@ -0,0 +1,34 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineImageUploadHandler } from 'prosekit/extensions/image' +import { defineMath } from 'prosekit/extensions/math' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' +import { sampleUploader } from '../../sample/sample-uploader' +import { defineCodeBlockView } from '../../ui/code-block-view' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + defineMention(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + defineCodeBlockShiki(), + defineHorizontalRule(), + defineCodeBlockView(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-full/src/components/editor/examples/full/index.ts b/solid-full/src/components/editor/examples/full/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-full/src/components/editor/examples/full/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-full/src/components/editor/sample/katex.ts b/solid-full/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/solid-full/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/solid-full/src/components/editor/sample/sample-doc-full.ts b/solid-full/src/components/editor/sample/sample-doc-full.ts new file mode 100644 index 0000000000..13e49b634d --- /dev/null +++ b/solid-full/src/components/editor/sample/sample-doc-full.ts @@ -0,0 +1,442 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'The editor that thinks like you' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', + }, + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'writing without barriers', + }, + { type: 'text', text: '.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Text that shines.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Make your words ' }, + { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, + { type: 'text', text: ', or ' }, + { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, + { type: 'text', text: '. Add ' }, + { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, + { type: 'text', text: ' that stands out. Create ' }, + { + type: 'text', + marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], + text: 'links', + }, + { type: 'text', text: ' that connect.' }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Select any text to format it. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '@' }, + { type: 'text', text: ' to mention ' }, + { + type: 'mention', + attrs: { id: '39', value: '@someone', kind: 'user' }, + }, + { type: 'text', text: ' or ' }, + { type: 'text', marks: [{ type: 'code' }], text: '#' }, + { type: 'text', text: ' for ' }, + { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, + { type: 'text', text: '. Press ' }, + { type: 'text', marks: [{ type: 'code' }], text: '/' }, + { type: 'text', text: " and discover what's possible." }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Lists that organize.' }], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Bullet points that guide thoughts' }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Nested lists for complex ideas' }], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sub-points flow naturally' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Tasks that focus' }], + }, + { + type: 'list', + attrs: { kind: 'task', order: null, checked: true, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Done feels good' }], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Todo drives action' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Numbered steps' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sequential thinking' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Clear progress' }], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Code that inspires.' }], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Images that captivate.' }], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/season/320x240/107', + }, + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the handle in the bottom right corner to resize.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Tables that structure.' }], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'Feature', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'How to use', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Format text' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Select and choose' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Perfect styling' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Add mentions' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Type @ and name' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Connected ideas' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Insert anything' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Press / for menu' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Endless possibilities' }], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Math that renders.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Inline math like ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' appears within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Quotes that inspire.' }], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: '"This is not just an editor. This is how writing should feel."', + }, + ], + }, + ], + }, + { type: 'horizontalRule' }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Start typing. Everything else just flows.' }, + ], + }, + ], +} diff --git a/solid-full/src/components/editor/sample/sample-tag-data.ts b/solid-full/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/solid-full/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/solid-full/src/components/editor/sample/sample-uploader.ts b/solid-full/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/solid-full/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/solid-full/src/components/editor/sample/sample-user-data.ts b/solid-full/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/solid-full/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/solid-full/src/components/editor/ui/block-handle/block-handle.tsx b/solid-full/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..95e1693ef6 --- /dev/null +++ b/solid-full/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,32 @@ +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/solid/block-handle' +import type { JSX } from 'solid-js' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props): JSX.Element { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/solid-full/src/components/editor/ui/block-handle/index.ts b/solid-full/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/solid-full/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/solid-full/src/components/editor/ui/button/button.tsx b/solid-full/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-full/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-full/src/components/editor/ui/button/index.ts b/solid-full/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-full/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-full/src/components/editor/ui/code-block-view/code-block-view.tsx b/solid-full/src/components/editor/ui/code-block-view/code-block-view.tsx new file mode 100644 index 0000000000..2d67b563f7 --- /dev/null +++ b/solid-full/src/components/editor/ui/code-block-view/code-block-view.tsx @@ -0,0 +1,36 @@ +import type { CodeBlockAttrs } from 'prosekit/extensions/code-block' +import { shikiBundledLanguagesInfo } from 'prosekit/extensions/code-block' +import type { SolidNodeViewProps } from 'prosekit/solid' +import { For, type JSX } from 'solid-js' + +export default function CodeBlockView(props: SolidNodeViewProps): JSX.Element { + const attrs = () => props.node.attrs as CodeBlockAttrs + const language = () => attrs().language + + const setLanguage = (lang: string) => { + const newAttrs: CodeBlockAttrs = { language: lang } + props.setAttrs(newAttrs) + } + + return ( + <> + +

+    
+  )
+}
diff --git a/solid-full/src/components/editor/ui/code-block-view/index.ts b/solid-full/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..50bbbea7df
--- /dev/null
+++ b/solid-full/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSolidNodeView,
+  type SolidNodeViewComponent,
+} from 'prosekit/solid'
+
+import CodeBlockView from './code-block-view'
+
+export function defineCodeBlockView(): Extension {
+  return defineSolidNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView satisfies SolidNodeViewComponent,
+  })
+}
diff --git a/solid-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/solid-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
new file mode 100644
index 0000000000..c5a24c7faa
--- /dev/null
+++ b/solid-full/src/components/editor/ui/drop-indicator/drop-indicator.tsx
@@ -0,0 +1,6 @@
+import { DropIndicator as BaseDropIndicator } from 'prosekit/solid/drop-indicator'
+import type { JSX } from 'solid-js'
+
+export default function DropIndicator(): JSX.Element {
+  return 
+}
diff --git a/solid-full/src/components/editor/ui/drop-indicator/index.ts b/solid-full/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..f8fb7139c4
--- /dev/null
+++ b/solid-full/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator'
diff --git a/solid-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
new file mode 100644
index 0000000000..efa306305f
--- /dev/null
+++ b/solid-full/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx
@@ -0,0 +1,137 @@
+import type { Uploader } from 'prosekit/extensions/file'
+import type { ImageExtension } from 'prosekit/extensions/image'
+import { useEditor } from 'prosekit/solid'
+import {
+  PopoverPopup,
+  PopoverPositioner,
+  PopoverRoot,
+  PopoverTrigger,
+} from 'prosekit/solid/popover'
+import type { OpenChangeEvent } from 'prosekit/web/popover'
+import { createSignal, createUniqueId, Show, type JSX } from 'solid-js'
+
+import { Button } from '../button'
+
+export default function ImageUploadPopover(props: {
+  uploader: Uploader
+  tooltip: string
+  disabled: boolean
+  children: JSX.Element
+}): JSX.Element {
+  const [open, setOpen] = createSignal(false)
+  const [url, setUrl] = createSignal('')
+  const [file, setFile] = createSignal(null)
+  const ariaId = createUniqueId()
+
+  const editor = useEditor()
+
+  const handleFileChange = (event: Event) => {
+    const target = event.target as HTMLInputElement
+    const selectedFile = target.files?.[0]
+
+    if (selectedFile) {
+      setFile(selectedFile)
+      setUrl('')
+    } else {
+      setFile(null)
+    }
+  }
+
+  const handleUrlChange = (event: Event) => {
+    const target = event.target as HTMLInputElement
+    const inputUrl = target.value
+
+    if (inputUrl) {
+      setUrl(inputUrl)
+      setFile(null)
+    } else {
+      setUrl('')
+    }
+  }
+
+  const deferResetState = () => {
+    setTimeout(() => {
+      setUrl('')
+      setFile(null)
+    }, 300)
+  }
+
+  const handleSubmit = () => {
+    if (url()) {
+      editor().commands.insertImage({ src: url() })
+    } else if (file()) {
+      editor().commands.uploadImage({ file: file()!, uploader: props.uploader })
+    }
+    setOpen(false)
+    deferResetState()
+  }
+
+  const handleOpenChange = (event: OpenChangeEvent) => {
+    if (!event.detail) {
+      deferResetState()
+    }
+    setOpen(event.detail)
+  }
+
+  return (
+    
+      
+        
+      
+
+      
+        
+          
+            
+            
+          
+
+          
+            
+            
+          
+
+          
+            
+          
+
+          
+            
+          
+        
+      
+    
+  )
+}
diff --git a/solid-full/src/components/editor/ui/image-upload-popover/index.ts b/solid-full/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..5d49d873ce
--- /dev/null
+++ b/solid-full/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover'
diff --git a/solid-full/src/components/editor/ui/image-view/image-view.tsx b/solid-full/src/components/editor/ui/image-view/image-view.tsx
new file mode 100644
index 0000000000..813fbec79c
--- /dev/null
+++ b/solid-full/src/components/editor/ui/image-view/image-view.tsx
@@ -0,0 +1,90 @@
+import { UploadTask } from 'prosekit/extensions/file'
+import type { ImageAttrs } from 'prosekit/extensions/image'
+import type { SolidNodeViewProps } from 'prosekit/solid'
+import { ResizableHandle, ResizableRoot } from 'prosekit/solid/resizable'
+import { createEffect, createSignal, onCleanup, Show, type JSX } from 'solid-js'
+
+export default function ImageView(props: SolidNodeViewProps): JSX.Element {
+  const attrs = () => props.node.attrs as ImageAttrs
+  const url = () => attrs().src || ''
+  const uploading = () => url().startsWith('blob:')
+
+  const [aspectRatio, setAspectRatio] = createSignal()
+  const [error, setError] = createSignal()
+  const [progress, setProgress] = createSignal(0)
+
+  createEffect(() => {
+    if (!uploading()) return
+
+    const uploadTask = UploadTask.get(url())
+    if (!uploadTask) return
+
+    let canceled = false
+
+    uploadTask.finished.catch((err) => {
+      if (canceled) return
+      setError(String(err))
+    })
+    const unsubscribeProgress = uploadTask.subscribeProgress(
+      ({ loaded, total }) => {
+        if (canceled) return
+        setProgress(total ? loaded / total : 0)
+      },
+    )
+
+    onCleanup(() => {
+      canceled = true
+      unsubscribeProgress()
+    })
+  })
+
+  const handleImageLoad = (event: Event) => {
+    const img = event.target as HTMLImageElement
+    const { naturalWidth, naturalHeight } = img
+    const ratio = naturalWidth / naturalHeight
+    if (ratio && Number.isFinite(ratio)) {
+      setAspectRatio(ratio)
+    }
+    if (naturalWidth && naturalHeight && (!attrs().width || !attrs().height)) {
+      props.setAttrs({ width: naturalWidth, height: naturalHeight })
+    }
+  }
+
+  return (
+     props.setAttrs(event.detail)}
+      attr:data-selected={props.selected ? '' : undefined}
+      class="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid"
+    >
+      
+        upload preview
+      
+      
+        
+
+
{Math.round(progress() * 100)}%
+
+
+ +
+
+ +
+
+ +
+
+
+ ) +} diff --git a/solid-full/src/components/editor/ui/image-view/index.ts b/solid-full/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..223c959559 --- /dev/null +++ b/solid-full/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + defineSolidNodeView, + type SolidNodeViewComponent, +} from 'prosekit/solid' + +import ImageView from './image-view' + +export function defineImageView(): Extension { + return defineSolidNodeView({ + name: 'image', + component: ImageView satisfies SolidNodeViewComponent, + }) +} diff --git a/solid-full/src/components/editor/ui/inline-menu/index.ts b/solid-full/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/solid-full/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/solid-full/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-full/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..d61df6d794 --- /dev/null +++ b/solid-full/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,233 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/solid' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/solid/inline-popover' +import { createSignal, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu(): JSX.Element { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor().commands.addLink({ href }) + } else { + editor().commands.removeLink() + } + + setLinkMenuOpen(false) + editor().focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + + + + {(item) => ( + setLinkMenuOpen(event.detail)} + > + + + +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+
+ + + +
+
+
+ )} +
+ + ) +} diff --git a/solid-full/src/components/editor/ui/slash-menu/index.ts b/solid-full/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/solid-full/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/solid-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/solid-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..aae5f3dc6b --- /dev/null +++ b/solid-full/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,10 @@ +import { AutocompleteEmpty } from 'prosekit/solid/autocomplete' +import type { JSX } from 'solid-js' + +export default function SlashMenuEmpty(): JSX.Element { + return ( + + No results + + ) +} diff --git a/solid-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/solid-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..9d8101d019 --- /dev/null +++ b/solid-full/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,22 @@ +import { AutocompleteItem } from 'prosekit/solid/autocomplete' +import { Show, type JSX } from 'solid-js' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}): JSX.Element { + return ( + + {props.label} + + + {props.kbd} + + + + ) +} diff --git a/solid-full/src/components/editor/ui/slash-menu/slash-menu.tsx b/solid-full/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..c7090d7f36 --- /dev/null +++ b/solid-full/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,101 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/solid' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/solid/autocomplete' +import type { JSX } from 'solid-js' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor().commands.setParagraph()} + /> + + editor().commands.setHeading({ level: 1 })} + /> + + editor().commands.setHeading({ level: 2 })} + /> + + editor().commands.setHeading({ level: 3 })} + /> + + editor().commands.wrapInList({ kind: 'bullet' })} + /> + + editor().commands.wrapInList({ kind: 'ordered' })} + /> + + editor().commands.wrapInList({ kind: 'task' })} + /> + + editor().commands.wrapInList({ kind: 'toggle' })} + /> + + editor().commands.setBlockquote()} + /> + + editor().commands.insertTable({ row: 3, col: 3 })} + /> + + editor().commands.insertHorizontalRule()} + /> + + editor().commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/solid-full/src/components/editor/ui/table-handle/index.ts b/solid-full/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/solid-full/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/solid-full/src/components/editor/ui/table-handle/table-handle.tsx b/solid-full/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..463f4d3657 --- /dev/null +++ b/solid-full/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,187 @@ +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/solid' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/solid/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/solid/table-handle' +import { Show, type JSX } from 'solid-js' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props): JSX.Element { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + + state().addTableColumnBefore.command()} + > + Insert Left + + + + state().addTableColumnAfter.command()} + > + Insert Right + + + + state().deleteCellSelection.command()} + > + Clear Contents + + Del + + + + + state().deleteTableColumn.command()} + > + Delete Column + + + + state().deleteTable.command()} + > + Delete Table + + + + +
+
+
+ + + + +
+
+ + + + state().addTableRowAbove.command()} + > + Insert Above + + + + state().addTableRowBelow.command()} + > + Insert Below + + + + state().deleteCellSelection.command()} + > + Clear Contents + + Del + + + + + state().deleteTableRow.command()} + > + Delete Row + + + + state().deleteTable.command()} + > + Delete Table + + + + +
+
+
+
+ ) +} diff --git a/solid-full/src/components/editor/ui/tag-menu/index.ts b/solid-full/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..d344b33a70 --- /dev/null +++ b/solid-full/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu' diff --git a/solid-full/src/components/editor/ui/tag-menu/tag-menu.tsx b/solid-full/src/components/editor/ui/tag-menu/tag-menu.tsx new file mode 100644 index 0000000000..03e3534da3 --- /dev/null +++ b/solid-full/src/components/editor/ui/tag-menu/tag-menu.tsx @@ -0,0 +1,54 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/solid' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/solid/autocomplete' +import { For, type JSX } from 'solid-js' + +const regex = /#[\da-z]*$/i + +export default function TagMenu(props: { + tags: { id: number; label: string }[] +}): JSX.Element { + const editor = useEditor>() + + const handleTagInsert = (id: number, label: string) => { + editor().commands.insertMention({ + id: id.toString(), + value: '#' + label, + kind: 'tag', + }) + editor().commands.insertText({ text: ' ' }) + } + + return ( + + + +
+ + No results + + + + {(tag) => ( + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + )} + +
+
+
+
+ ) +} diff --git a/solid-full/src/components/editor/ui/toolbar/index.ts b/solid-full/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-full/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-full/src/components/editor/ui/toolbar/toolbar.tsx b/solid-full/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-full/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-full/src/components/editor/ui/user-menu/index.ts b/solid-full/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/solid-full/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/solid-full/src/components/editor/ui/user-menu/user-menu.tsx b/solid-full/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..61d3cd96d8 --- /dev/null +++ b/solid-full/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,64 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/solid' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/solid/autocomplete' +import { For, type JSX } from 'solid-js' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}): JSX.Element { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor().commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor().commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + + {(user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + )} + +
+
+
+
+ ) +} diff --git a/solid-full/src/index.tsx b/solid-full/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-full/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-full/tsconfig.app.json b/solid-full/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-full/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-full/tsconfig.json b/solid-full/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-full/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-full/tsconfig.node.json b/solid-full/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-full/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-full/vite.config.ts b/solid-full/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-full/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-gap-cursor/.gitignore b/solid-gap-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-gap-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-gap-cursor/README.md b/solid-gap-cursor/README.md new file mode 100644 index 0000000000..6c119ab2a7 --- /dev/null +++ b/solid-gap-cursor/README.md @@ -0,0 +1,15 @@ +# solid-gap-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-gap-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-gap-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-gap-cursor solid-gap-cursor +cd solid-gap-cursor +npm install +npm run dev +``` diff --git a/solid-gap-cursor/index.html b/solid-gap-cursor/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-gap-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-gap-cursor/package.json b/solid-gap-cursor/package.json new file mode 100644 index 0000000000..f1bd270cd7 --- /dev/null +++ b/solid-gap-cursor/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-gap-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-gap-cursor/src/App.tsx b/solid-gap-cursor/src/App.tsx new file mode 100644 index 0000000000..ed7e74417e --- /dev/null +++ b/solid-gap-cursor/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/gap-cursor' + +export default function App() { + return +} diff --git a/solid-gap-cursor/src/app.css b/solid-gap-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-gap-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx b/solid-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx new file mode 100644 index 0000000000..71e17b574a --- /dev/null +++ b/solid-gap-cursor/src/components/editor/examples/gap-cursor/editor.tsx @@ -0,0 +1,33 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-gap-cursor' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/solid-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts new file mode 100644 index 0000000000..599497170d --- /dev/null +++ b/solid-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts @@ -0,0 +1,19 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineGapCursor(), + defineImage(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/solid-gap-cursor/src/components/editor/examples/gap-cursor/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-gap-cursor/src/components/editor/examples/gap-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/solid-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts new file mode 100644 index 0000000000..e40ee2a83b --- /dev/null +++ b/solid-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts @@ -0,0 +1,28 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + ], +} diff --git a/solid-gap-cursor/src/index.tsx b/solid-gap-cursor/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-gap-cursor/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-gap-cursor/tsconfig.app.json b/solid-gap-cursor/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-gap-cursor/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-gap-cursor/tsconfig.json b/solid-gap-cursor/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-gap-cursor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-gap-cursor/tsconfig.node.json b/solid-gap-cursor/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-gap-cursor/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-gap-cursor/vite.config.ts b/solid-gap-cursor/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-gap-cursor/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-hard-break/.gitignore b/solid-hard-break/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-hard-break/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-hard-break/README.md b/solid-hard-break/README.md new file mode 100644 index 0000000000..c9ebb60380 --- /dev/null +++ b/solid-hard-break/README.md @@ -0,0 +1,15 @@ +# solid-hard-break + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-hard-break) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-hard-break) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-hard-break solid-hard-break +cd solid-hard-break +npm install +npm run dev +``` diff --git a/solid-hard-break/index.html b/solid-hard-break/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-hard-break/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-hard-break/package.json b/solid-hard-break/package.json new file mode 100644 index 0000000000..69c0a26a46 --- /dev/null +++ b/solid-hard-break/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-hard-break", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-hard-break/src/App.tsx b/solid-hard-break/src/App.tsx new file mode 100644 index 0000000000..db3ea90c2a --- /dev/null +++ b/solid-hard-break/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/hard-break' + +export default function App() { + return +} diff --git a/solid-hard-break/src/app.css b/solid-hard-break/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-hard-break/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-hard-break/src/components/editor/examples/hard-break/editor.tsx b/solid-hard-break/src/components/editor/examples/hard-break/editor.tsx new file mode 100644 index 0000000000..26023e10f6 --- /dev/null +++ b/solid-hard-break/src/components/editor/examples/hard-break/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-hard-break' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-hard-break/src/components/editor/examples/hard-break/extension.ts b/solid-hard-break/src/components/editor/examples/hard-break/extension.ts new file mode 100644 index 0000000000..cad2881056 --- /dev/null +++ b/solid-hard-break/src/components/editor/examples/hard-break/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHardBreak } from 'prosekit/extensions/hard-break' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHardBreak(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-hard-break/src/components/editor/examples/hard-break/index.ts b/solid-hard-break/src/components/editor/examples/hard-break/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-hard-break/src/components/editor/examples/hard-break/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-hard-break/src/components/editor/examples/hard-break/toolbar.tsx b/solid-hard-break/src/components/editor/examples/hard-break/toolbar.tsx new file mode 100644 index 0000000000..f6b8cd5d44 --- /dev/null +++ b/solid-hard-break/src/components/editor/examples/hard-break/toolbar.tsx @@ -0,0 +1,32 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + hardBreak: { + canExec: editor.commands.insertHardBreak.canExec(), + command: () => editor.commands.insertHardBreak(), + }, + } +} + +export default function Toolbar(): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/solid-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/solid-hard-break/src/components/editor/sample/sample-doc-hard-break.ts new file mode 100644 index 0000000000..e1c9786b72 --- /dev/null +++ b/solid-hard-break/src/components/editor/sample/sample-doc-hard-break.ts @@ -0,0 +1,68 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: "O'er all the hilltops", + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Is quiet now,', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'In all the treetops', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hearest thou', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hardly a breath;', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'The birds are asleep in the trees:', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Wait, soon like these', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Thou too shalt rest.', + }, + { + type: 'hardBreak', + }, + ], + }, + ], +} diff --git a/solid-hard-break/src/components/editor/ui/button/button.tsx b/solid-hard-break/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-hard-break/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-hard-break/src/components/editor/ui/button/index.ts b/solid-hard-break/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-hard-break/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-hard-break/src/index.tsx b/solid-hard-break/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-hard-break/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-hard-break/tsconfig.app.json b/solid-hard-break/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-hard-break/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-hard-break/tsconfig.json b/solid-hard-break/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-hard-break/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-hard-break/tsconfig.node.json b/solid-hard-break/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-hard-break/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-hard-break/vite.config.ts b/solid-hard-break/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-hard-break/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-heading/.gitignore b/solid-heading/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-heading/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-heading/README.md b/solid-heading/README.md new file mode 100644 index 0000000000..782676d80f --- /dev/null +++ b/solid-heading/README.md @@ -0,0 +1,15 @@ +# solid-heading + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-heading) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-heading) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-heading solid-heading +cd solid-heading +npm install +npm run dev +``` diff --git a/solid-heading/index.html b/solid-heading/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-heading/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-heading/package.json b/solid-heading/package.json new file mode 100644 index 0000000000..b7e5fb196d --- /dev/null +++ b/solid-heading/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-heading", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-heading/src/App.tsx b/solid-heading/src/App.tsx new file mode 100644 index 0000000000..c70e72d05f --- /dev/null +++ b/solid-heading/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/heading' + +export default function App() { + return +} diff --git a/solid-heading/src/app.css b/solid-heading/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-heading/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-heading/src/components/editor/examples/heading/editor.tsx b/solid-heading/src/components/editor/examples/heading/editor.tsx new file mode 100644 index 0000000000..dadd87e073 --- /dev/null +++ b/solid-heading/src/components/editor/examples/heading/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-heading' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-heading/src/components/editor/examples/heading/extension.ts b/solid-heading/src/components/editor/examples/heading/extension.ts new file mode 100644 index 0000000000..e4f8e6ace0 --- /dev/null +++ b/solid-heading/src/components/editor/examples/heading/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHeading(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-heading/src/components/editor/examples/heading/index.ts b/solid-heading/src/components/editor/examples/heading/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-heading/src/components/editor/examples/heading/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-heading/src/components/editor/sample/sample-doc-heading.ts b/solid-heading/src/components/editor/sample/sample-doc-heading.ts new file mode 100644 index 0000000000..210497e633 --- /dev/null +++ b/solid-heading/src/components/editor/sample/sample-doc-heading.ts @@ -0,0 +1,23 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'H1' }], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'H2' }], + }, + { + type: 'heading', + attrs: { level: 3 }, + content: [{ type: 'text', text: 'H3' }], + }, + { type: 'paragraph', content: [] }, + ], +} diff --git a/solid-heading/src/components/editor/ui/button/button.tsx b/solid-heading/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-heading/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-heading/src/components/editor/ui/button/index.ts b/solid-heading/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-heading/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-heading/src/components/editor/ui/image-upload-popover/index.ts b/solid-heading/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-heading/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-heading/src/components/editor/ui/toolbar/index.ts b/solid-heading/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-heading/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-heading/src/components/editor/ui/toolbar/toolbar.tsx b/solid-heading/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-heading/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-heading/src/index.tsx b/solid-heading/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-heading/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-heading/tsconfig.app.json b/solid-heading/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-heading/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-heading/tsconfig.json b/solid-heading/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-heading/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-heading/tsconfig.node.json b/solid-heading/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-heading/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-heading/vite.config.ts b/solid-heading/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-heading/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-highlight/.gitignore b/solid-highlight/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-highlight/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-highlight/README.md b/solid-highlight/README.md new file mode 100644 index 0000000000..50c7d5eb90 --- /dev/null +++ b/solid-highlight/README.md @@ -0,0 +1,15 @@ +# solid-highlight + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-highlight) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-highlight) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-highlight solid-highlight +cd solid-highlight +npm install +npm run dev +``` diff --git a/solid-highlight/index.html b/solid-highlight/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-highlight/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-highlight/package.json b/solid-highlight/package.json new file mode 100644 index 0000000000..00521fa729 --- /dev/null +++ b/solid-highlight/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-highlight", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-highlight/src/App.tsx b/solid-highlight/src/App.tsx new file mode 100644 index 0000000000..2509b001f7 --- /dev/null +++ b/solid-highlight/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/highlight' + +export default function App() { + return +} diff --git a/solid-highlight/src/app.css b/solid-highlight/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-highlight/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-highlight/src/components/editor/examples/highlight/editor.tsx b/solid-highlight/src/components/editor/examples/highlight/editor.tsx new file mode 100644 index 0000000000..3e0286fd2d --- /dev/null +++ b/solid-highlight/src/components/editor/examples/highlight/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-highlight' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-highlight/src/components/editor/examples/highlight/extension.ts b/solid-highlight/src/components/editor/examples/highlight/extension.ts new file mode 100644 index 0000000000..abc131c3be --- /dev/null +++ b/solid-highlight/src/components/editor/examples/highlight/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHighlight } from 'prosekit/extensions/highlight' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHighlight(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-highlight/src/components/editor/examples/highlight/index.ts b/solid-highlight/src/components/editor/examples/highlight/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-highlight/src/components/editor/examples/highlight/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-highlight/src/components/editor/examples/highlight/toolbar.tsx b/solid-highlight/src/components/editor/examples/highlight/toolbar.tsx new file mode 100644 index 0000000000..51f99b085e --- /dev/null +++ b/solid-highlight/src/components/editor/examples/highlight/toolbar.tsx @@ -0,0 +1,33 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + highlight: { + isActive: editor.marks.highlight.isActive(), + canExec: editor.commands.toggleHighlight.canExec(), + command: () => editor.commands.toggleHighlight(), + }, + } +} + +export default function Toolbar(): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/solid-highlight/src/components/editor/sample/sample-doc-highlight.ts b/solid-highlight/src/components/editor/sample/sample-doc-highlight.ts new file mode 100644 index 0000000000..0de1a1f7b2 --- /dev/null +++ b/solid-highlight/src/components/editor/sample/sample-doc-highlight.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'highlight', + }, + ], + text: 'This is highlighted text', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/solid-highlight/src/components/editor/ui/button/button.tsx b/solid-highlight/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-highlight/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-highlight/src/components/editor/ui/button/index.ts b/solid-highlight/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-highlight/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-highlight/src/index.tsx b/solid-highlight/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-highlight/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-highlight/tsconfig.app.json b/solid-highlight/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-highlight/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-highlight/tsconfig.json b/solid-highlight/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-highlight/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-highlight/tsconfig.node.json b/solid-highlight/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-highlight/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-highlight/vite.config.ts b/solid-highlight/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-highlight/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-horizontal-rule/.gitignore b/solid-horizontal-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-horizontal-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-horizontal-rule/README.md b/solid-horizontal-rule/README.md new file mode 100644 index 0000000000..55d142f837 --- /dev/null +++ b/solid-horizontal-rule/README.md @@ -0,0 +1,15 @@ +# solid-horizontal-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-horizontal-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-horizontal-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-horizontal-rule solid-horizontal-rule +cd solid-horizontal-rule +npm install +npm run dev +``` diff --git a/solid-horizontal-rule/index.html b/solid-horizontal-rule/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-horizontal-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-horizontal-rule/package.json b/solid-horizontal-rule/package.json new file mode 100644 index 0000000000..50de4ddba7 --- /dev/null +++ b/solid-horizontal-rule/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-horizontal-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-horizontal-rule/src/App.tsx b/solid-horizontal-rule/src/App.tsx new file mode 100644 index 0000000000..974e387364 --- /dev/null +++ b/solid-horizontal-rule/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/horizontal-rule' + +export default function App() { + return +} diff --git a/solid-horizontal-rule/src/app.css b/solid-horizontal-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-horizontal-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx new file mode 100644 index 0000000000..05c47ad54e --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.tsx @@ -0,0 +1,29 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts new file mode 100644 index 0000000000..49b6121eeb --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHorizontalRule(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-horizontal-rule/src/components/editor/ui/button/button.tsx b/solid-horizontal-rule/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-horizontal-rule/src/components/editor/ui/button/index.ts b/solid-horizontal-rule/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/solid-horizontal-rule/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx b/solid-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-horizontal-rule/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-horizontal-rule/src/index.tsx b/solid-horizontal-rule/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-horizontal-rule/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-horizontal-rule/tsconfig.app.json b/solid-horizontal-rule/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-horizontal-rule/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-horizontal-rule/tsconfig.json b/solid-horizontal-rule/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-horizontal-rule/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-horizontal-rule/tsconfig.node.json b/solid-horizontal-rule/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-horizontal-rule/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-horizontal-rule/vite.config.ts b/solid-horizontal-rule/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-horizontal-rule/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-image-view/.gitignore b/solid-image-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-image-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-image-view/README.md b/solid-image-view/README.md new file mode 100644 index 0000000000..23192c5114 --- /dev/null +++ b/solid-image-view/README.md @@ -0,0 +1,15 @@ +# solid-image-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-image-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-image-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-image-view solid-image-view +cd solid-image-view +npm install +npm run dev +``` diff --git a/solid-image-view/index.html b/solid-image-view/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-image-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-image-view/package.json b/solid-image-view/package.json new file mode 100644 index 0000000000..cb49e68435 --- /dev/null +++ b/solid-image-view/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-image-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-image-view/src/App.tsx b/solid-image-view/src/App.tsx new file mode 100644 index 0000000000..46ede58891 --- /dev/null +++ b/solid-image-view/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/image-view' + +export default function App() { + return +} diff --git a/solid-image-view/src/app.css b/solid-image-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-image-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-image-view/src/components/editor/examples/image-view/editor.tsx b/solid-image-view/src/components/editor/examples/image-view/editor.tsx new file mode 100644 index 0000000000..e663c70392 --- /dev/null +++ b/solid-image-view/src/components/editor/examples/image-view/editor.tsx @@ -0,0 +1,33 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-image' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-image-view/src/components/editor/examples/image-view/extension.ts b/solid-image-view/src/components/editor/examples/image-view/extension.ts new file mode 100644 index 0000000000..a21febf634 --- /dev/null +++ b/solid-image-view/src/components/editor/examples/image-view/extension.ts @@ -0,0 +1,18 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineImageUploadHandler } from 'prosekit/extensions/image' + +import { sampleUploader } from '../../sample/sample-uploader' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-image-view/src/components/editor/examples/image-view/index.ts b/solid-image-view/src/components/editor/examples/image-view/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-image-view/src/components/editor/examples/image-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-image-view/src/components/editor/sample/sample-doc-image.ts b/solid-image-view/src/components/editor/sample/sample-doc-image.ts new file mode 100644 index 0000000000..c97628339d --- /dev/null +++ b/solid-image-view/src/components/editor/sample/sample-doc-image.ts @@ -0,0 +1,32 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Paste or drop an image to upload it.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/white/200x200/1', + width: 160, + height: 160, + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/640x360/42', + width: 240, + height: 135, + }, + }, + ], +} diff --git a/solid-image-view/src/components/editor/sample/sample-uploader.ts b/solid-image-view/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/solid-image-view/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/solid-image-view/src/components/editor/ui/image-view/image-view.tsx b/solid-image-view/src/components/editor/ui/image-view/image-view.tsx new file mode 100644 index 0000000000..813fbec79c --- /dev/null +++ b/solid-image-view/src/components/editor/ui/image-view/image-view.tsx @@ -0,0 +1,90 @@ +import { UploadTask } from 'prosekit/extensions/file' +import type { ImageAttrs } from 'prosekit/extensions/image' +import type { SolidNodeViewProps } from 'prosekit/solid' +import { ResizableHandle, ResizableRoot } from 'prosekit/solid/resizable' +import { createEffect, createSignal, onCleanup, Show, type JSX } from 'solid-js' + +export default function ImageView(props: SolidNodeViewProps): JSX.Element { + const attrs = () => props.node.attrs as ImageAttrs + const url = () => attrs().src || '' + const uploading = () => url().startsWith('blob:') + + const [aspectRatio, setAspectRatio] = createSignal() + const [error, setError] = createSignal() + const [progress, setProgress] = createSignal(0) + + createEffect(() => { + if (!uploading()) return + + const uploadTask = UploadTask.get(url()) + if (!uploadTask) return + + let canceled = false + + uploadTask.finished.catch((err) => { + if (canceled) return + setError(String(err)) + }) + const unsubscribeProgress = uploadTask.subscribeProgress( + ({ loaded, total }) => { + if (canceled) return + setProgress(total ? loaded / total : 0) + }, + ) + + onCleanup(() => { + canceled = true + unsubscribeProgress() + }) + }) + + const handleImageLoad = (event: Event) => { + const img = event.target as HTMLImageElement + const { naturalWidth, naturalHeight } = img + const ratio = naturalWidth / naturalHeight + if (ratio && Number.isFinite(ratio)) { + setAspectRatio(ratio) + } + if (naturalWidth && naturalHeight && (!attrs().width || !attrs().height)) { + props.setAttrs({ width: naturalWidth, height: naturalHeight }) + } + } + + return ( + props.setAttrs(event.detail)} + attr:data-selected={props.selected ? '' : undefined} + class="relative flex items-center justify-center box-border overflow-hidden my-2 group max-h-150 max-w-full min-h-16 min-w-16 outline-2 outline-transparent data-selected:outline-blue-500 outline-solid" + > + + upload preview + + +
+
+
{Math.round(progress() * 100)}%
+
+
+ +
+
+ +
+
+ +
+
+
+ ) +} diff --git a/solid-image-view/src/components/editor/ui/image-view/index.ts b/solid-image-view/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..223c959559 --- /dev/null +++ b/solid-image-view/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + defineSolidNodeView, + type SolidNodeViewComponent, +} from 'prosekit/solid' + +import ImageView from './image-view' + +export function defineImageView(): Extension { + return defineSolidNodeView({ + name: 'image', + component: ImageView satisfies SolidNodeViewComponent, + }) +} diff --git a/solid-image-view/src/index.tsx b/solid-image-view/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-image-view/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-image-view/tsconfig.app.json b/solid-image-view/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-image-view/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-image-view/tsconfig.json b/solid-image-view/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-image-view/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-image-view/tsconfig.node.json b/solid-image-view/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-image-view/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-image-view/vite.config.ts b/solid-image-view/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-image-view/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-inline-menu/.gitignore b/solid-inline-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-inline-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-inline-menu/README.md b/solid-inline-menu/README.md new file mode 100644 index 0000000000..ba8971772b --- /dev/null +++ b/solid-inline-menu/README.md @@ -0,0 +1,15 @@ +# solid-inline-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-inline-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-inline-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-inline-menu solid-inline-menu +cd solid-inline-menu +npm install +npm run dev +``` diff --git a/solid-inline-menu/index.html b/solid-inline-menu/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-inline-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-inline-menu/package.json b/solid-inline-menu/package.json new file mode 100644 index 0000000000..d4435d25a3 --- /dev/null +++ b/solid-inline-menu/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-inline-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-inline-menu/src/App.tsx b/solid-inline-menu/src/App.tsx new file mode 100644 index 0000000000..660285db3c --- /dev/null +++ b/solid-inline-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/inline-menu' + +export default function App() { + return +} diff --git a/solid-inline-menu/src/app.css b/solid-inline-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-inline-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-inline-menu/src/components/editor/examples/inline-menu/editor.tsx b/solid-inline-menu/src/components/editor/examples/inline-menu/editor.tsx new file mode 100644 index 0000000000..0ae17e6234 --- /dev/null +++ b/solid-inline-menu/src/components/editor/examples/inline-menu/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-inline-menu' +import { InlineMenu } from '../../ui/inline-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/solid-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/solid-inline-menu/src/components/editor/examples/inline-menu/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/solid-inline-menu/src/components/editor/examples/inline-menu/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/solid-inline-menu/src/components/editor/examples/inline-menu/index.ts b/solid-inline-menu/src/components/editor/examples/inline-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-inline-menu/src/components/editor/examples/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/solid-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts new file mode 100644 index 0000000000..62a5984cb0 --- /dev/null +++ b/solid-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts @@ -0,0 +1,33 @@ +import type { NodeJSON } from 'prosekit/core' + +const loremText = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'Try to select some text', + }, + ], + }, + ...Array.from({ length: 10 }, () => ({ + type: 'paragraph' as const, + content: [ + { + type: 'text' as const, + text: loremText, + }, + ], + })), + ], +} diff --git a/solid-inline-menu/src/components/editor/ui/button/button.tsx b/solid-inline-menu/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-inline-menu/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-inline-menu/src/components/editor/ui/button/index.ts b/solid-inline-menu/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-inline-menu/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-inline-menu/src/components/editor/ui/inline-menu/index.ts b/solid-inline-menu/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/solid-inline-menu/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/solid-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..d61df6d794 --- /dev/null +++ b/solid-inline-menu/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,233 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/solid' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/solid/inline-popover' +import { createSignal, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu(): JSX.Element { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor().commands.addLink({ href }) + } else { + editor().commands.removeLink() + } + + setLinkMenuOpen(false) + editor().focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + + + + {(item) => ( + setLinkMenuOpen(event.detail)} + > + + + +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+
+ + + +
+
+
+ )} +
+ + ) +} diff --git a/solid-inline-menu/src/index.tsx b/solid-inline-menu/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-inline-menu/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-inline-menu/tsconfig.app.json b/solid-inline-menu/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-inline-menu/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-inline-menu/tsconfig.json b/solid-inline-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-inline-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-inline-menu/tsconfig.node.json b/solid-inline-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-inline-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-inline-menu/vite.config.ts b/solid-inline-menu/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-inline-menu/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-italic/.gitignore b/solid-italic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-italic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-italic/README.md b/solid-italic/README.md new file mode 100644 index 0000000000..af60a0a836 --- /dev/null +++ b/solid-italic/README.md @@ -0,0 +1,15 @@ +# solid-italic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-italic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-italic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-italic solid-italic +cd solid-italic +npm install +npm run dev +``` diff --git a/solid-italic/index.html b/solid-italic/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-italic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-italic/package.json b/solid-italic/package.json new file mode 100644 index 0000000000..56c9635125 --- /dev/null +++ b/solid-italic/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-italic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-italic/src/App.tsx b/solid-italic/src/App.tsx new file mode 100644 index 0000000000..7ce968b449 --- /dev/null +++ b/solid-italic/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/italic' + +export default function App() { + return +} diff --git a/solid-italic/src/app.css b/solid-italic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-italic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-italic/src/components/editor/examples/italic/editor.tsx b/solid-italic/src/components/editor/examples/italic/editor.tsx new file mode 100644 index 0000000000..db8458677d --- /dev/null +++ b/solid-italic/src/components/editor/examples/italic/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-italic' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-italic/src/components/editor/examples/italic/extension.ts b/solid-italic/src/components/editor/examples/italic/extension.ts new file mode 100644 index 0000000000..a456b06aad --- /dev/null +++ b/solid-italic/src/components/editor/examples/italic/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineItalic(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-italic/src/components/editor/examples/italic/index.ts b/solid-italic/src/components/editor/examples/italic/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-italic/src/components/editor/examples/italic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-italic/src/components/editor/sample/sample-doc-italic.ts b/solid-italic/src/components/editor/sample/sample-doc-italic.ts new file mode 100644 index 0000000000..fb99415b2c --- /dev/null +++ b/solid-italic/src/components/editor/sample/sample-doc-italic.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/solid-italic/src/components/editor/ui/button/button.tsx b/solid-italic/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-italic/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-italic/src/components/editor/ui/button/index.ts b/solid-italic/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-italic/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-italic/src/components/editor/ui/image-upload-popover/index.ts b/solid-italic/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-italic/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-italic/src/components/editor/ui/toolbar/index.ts b/solid-italic/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-italic/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-italic/src/components/editor/ui/toolbar/toolbar.tsx b/solid-italic/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-italic/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-italic/src/index.tsx b/solid-italic/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-italic/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-italic/tsconfig.app.json b/solid-italic/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-italic/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-italic/tsconfig.json b/solid-italic/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-italic/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-italic/tsconfig.node.json b/solid-italic/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-italic/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-italic/vite.config.ts b/solid-italic/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-italic/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-katex/.gitignore b/solid-katex/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-katex/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-katex/README.md b/solid-katex/README.md new file mode 100644 index 0000000000..b256116f5a --- /dev/null +++ b/solid-katex/README.md @@ -0,0 +1,15 @@ +# solid-katex + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-katex) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-katex) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-katex solid-katex +cd solid-katex +npm install +npm run dev +``` diff --git a/solid-katex/index.html b/solid-katex/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-katex/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-katex/package.json b/solid-katex/package.json new file mode 100644 index 0000000000..9c94ee55b1 --- /dev/null +++ b/solid-katex/package.json @@ -0,0 +1,26 @@ +{ + "name": "example-solid-katex", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-katex/src/App.tsx b/solid-katex/src/App.tsx new file mode 100644 index 0000000000..2a28c7c7d7 --- /dev/null +++ b/solid-katex/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/katex' + +export default function App() { + return +} diff --git a/solid-katex/src/app.css b/solid-katex/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-katex/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-katex/src/components/editor/examples/katex/editor.tsx b/solid-katex/src/components/editor/examples/katex/editor.tsx new file mode 100644 index 0000000000..11c41d38d9 --- /dev/null +++ b/solid-katex/src/components/editor/examples/katex/editor.tsx @@ -0,0 +1,33 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-tex' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-katex/src/components/editor/examples/katex/extension.ts b/solid-katex/src/components/editor/examples/katex/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/solid-katex/src/components/editor/examples/katex/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-katex/src/components/editor/examples/katex/index.ts b/solid-katex/src/components/editor/examples/katex/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-katex/src/components/editor/examples/katex/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-katex/src/components/editor/sample/katex.ts b/solid-katex/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/solid-katex/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/solid-katex/src/components/editor/sample/sample-doc-tex.ts b/solid-katex/src/components/editor/sample/sample-doc-tex.ts new file mode 100644 index 0000000000..21ccf3e94e --- /dev/null +++ b/solid-katex/src/components/editor/sample/sample-doc-tex.ts @@ -0,0 +1,60 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Inline equations' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Block equations' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: 'The Gaussian integral:' }], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + ], +} diff --git a/solid-katex/src/index.tsx b/solid-katex/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-katex/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-katex/tsconfig.app.json b/solid-katex/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-katex/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-katex/tsconfig.json b/solid-katex/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-katex/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-katex/tsconfig.node.json b/solid-katex/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-katex/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-katex/vite.config.ts b/solid-katex/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-katex/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-keymap/.gitignore b/solid-keymap/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-keymap/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-keymap/README.md b/solid-keymap/README.md new file mode 100644 index 0000000000..3a877afd76 --- /dev/null +++ b/solid-keymap/README.md @@ -0,0 +1,15 @@ +# solid-keymap + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-keymap) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-keymap) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-keymap solid-keymap +cd solid-keymap +npm install +npm run dev +``` diff --git a/solid-keymap/index.html b/solid-keymap/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-keymap/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-keymap/package.json b/solid-keymap/package.json new file mode 100644 index 0000000000..061422dd15 --- /dev/null +++ b/solid-keymap/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-keymap", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-keymap/src/App.tsx b/solid-keymap/src/App.tsx new file mode 100644 index 0000000000..da3b6ebb09 --- /dev/null +++ b/solid-keymap/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/keymap' + +export default function App() { + return +} diff --git a/solid-keymap/src/app.css b/solid-keymap/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-keymap/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-keymap/src/components/editor/examples/keymap/editor.tsx b/solid-keymap/src/components/editor/examples/keymap/editor.tsx new file mode 100644 index 0000000000..ba3040419a --- /dev/null +++ b/solid-keymap/src/components/editor/examples/keymap/editor.tsx @@ -0,0 +1,51 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import { createSignal, For, Show, type JSX } from 'solid-js' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + const [submissions, setSubmissions] = createSignal([]) + + const pushSubmission = (hotkey: string) => { + const docString = JSON.stringify(editor.getDocJSON()) + const submission = `${new Date().toISOString()} ${hotkey} +${docString}` + setSubmissions((prev) => [...prev, submission]) + } + + return ( + +
+ +
+
+
+
+
+ Submit Records +
    + + {(submission) => ( +
  1. +
    {submission}
    +
  2. + )} +
    +
+ +
No submissions yet
+
+
+
+ ) +} diff --git a/solid-keymap/src/components/editor/examples/keymap/extension.ts b/solid-keymap/src/components/editor/examples/keymap/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/solid-keymap/src/components/editor/examples/keymap/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/solid-keymap/src/components/editor/examples/keymap/index.ts b/solid-keymap/src/components/editor/examples/keymap/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-keymap/src/components/editor/examples/keymap/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-keymap/src/components/editor/examples/keymap/toolbar.tsx b/solid-keymap/src/components/editor/examples/keymap/toolbar.tsx new file mode 100644 index 0000000000..81d1152976 --- /dev/null +++ b/solid-keymap/src/components/editor/examples/keymap/toolbar.tsx @@ -0,0 +1,31 @@ +import { createSignal, type JSX } from 'solid-js' + +import { Button } from '../../ui/button' + +import { useSubmitKeymap } from './use-submit-keymap' + +export default function Toolbar(props: { + onSubmit: (hotkey: string) => void +}): JSX.Element { + const [hotkey, setHotkey] = createSignal<'Shift-Enter' | 'Enter'>( + 'Shift-Enter', + ) + useSubmitKeymap(hotkey, props.onSubmit) + + return ( +
+ + + +
+ ) +} diff --git a/solid-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts b/solid-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts new file mode 100644 index 0000000000..941fc50744 --- /dev/null +++ b/solid-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts @@ -0,0 +1,20 @@ +import type { Keymap } from 'prosekit/core' +import { useKeymap } from 'prosekit/solid' +import type { Accessor } from 'solid-js' + +export function useSubmitKeymap( + hotkey: Accessor<'Shift-Enter' | 'Enter'>, + onSubmit: (hotkey: string) => void, +): void { + const keymap = () => { + const currentHotkey = hotkey() + return { + [currentHotkey]: () => { + onSubmit(currentHotkey) + return true + }, + } satisfies Keymap + } + + useKeymap(keymap) +} diff --git a/solid-keymap/src/components/editor/ui/button/button.tsx b/solid-keymap/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-keymap/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-keymap/src/components/editor/ui/button/index.ts b/solid-keymap/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-keymap/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-keymap/src/index.tsx b/solid-keymap/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-keymap/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-keymap/tsconfig.app.json b/solid-keymap/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-keymap/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-keymap/tsconfig.json b/solid-keymap/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-keymap/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-keymap/tsconfig.node.json b/solid-keymap/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-keymap/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-keymap/vite.config.ts b/solid-keymap/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-keymap/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-link-mark-view/.gitignore b/solid-link-mark-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-link-mark-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-link-mark-view/README.md b/solid-link-mark-view/README.md new file mode 100644 index 0000000000..29752ace96 --- /dev/null +++ b/solid-link-mark-view/README.md @@ -0,0 +1,15 @@ +# solid-link-mark-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-link-mark-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-link-mark-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-link-mark-view solid-link-mark-view +cd solid-link-mark-view +npm install +npm run dev +``` diff --git a/solid-link-mark-view/index.html b/solid-link-mark-view/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-link-mark-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-link-mark-view/package.json b/solid-link-mark-view/package.json new file mode 100644 index 0000000000..f195c0b5e2 --- /dev/null +++ b/solid-link-mark-view/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-link-mark-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-link-mark-view/src/App.tsx b/solid-link-mark-view/src/App.tsx new file mode 100644 index 0000000000..8a8685678d --- /dev/null +++ b/solid-link-mark-view/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/link-mark-view' + +export default function App() { + return +} diff --git a/solid-link-mark-view/src/app.css b/solid-link-mark-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-link-mark-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx b/solid-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx new file mode 100644 index 0000000000..d4bd398bbd --- /dev/null +++ b/solid-link-mark-view/src/components/editor/examples/link-mark-view/editor.tsx @@ -0,0 +1,33 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-link-mark-view' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/solid-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts new file mode 100644 index 0000000000..019835bd63 --- /dev/null +++ b/solid-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineSolidMarkView } from 'prosekit/solid' + +import LinkView from './link-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineSolidMarkView({ + name: 'link', + component: LinkView, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/solid-link-mark-view/src/components/editor/examples/link-mark-view/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-link-mark-view/src/components/editor/examples/link-mark-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx b/solid-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx new file mode 100644 index 0000000000..fc3351544d --- /dev/null +++ b/solid-link-mark-view/src/components/editor/examples/link-mark-view/link-view.tsx @@ -0,0 +1,46 @@ +import type { SolidMarkViewProps } from 'prosekit/solid' +import { createSignal, onCleanup, onMount, type JSX } from 'solid-js' + +const colors = [ + '#f06292', + '#ba68c8', + '#9575cd', + '#7986cb', + '#64b5f6', + '#4fc3f7', + '#4dd0e1', + '#4db6ac', + '#81c784', + '#aed581', + '#ffb74d', + '#ffa726', + '#ff8a65', + '#d4e157', + '#ffd54f', + '#ffecb3', +] + +function pickRandomColor() { + return colors[Math.floor(Math.random() * colors.length)] +} + +export default function Link(props: SolidMarkViewProps): JSX.Element { + const [color, setColor] = createSignal(colors[0]) + const href = props.mark.attrs.href as string + + onMount(() => { + const interval = setInterval(() => { + setColor(pickRandomColor()) + }, 1000) + + onCleanup(() => clearInterval(interval)) + }) + + return ( + + ) +} diff --git a/solid-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/solid-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts new file mode 100644 index 0000000000..57abd09dd6 --- /dev/null +++ b/solid-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is a link that changes color every second: ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/solid-link-mark-view/src/index.tsx b/solid-link-mark-view/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-link-mark-view/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-link-mark-view/tsconfig.app.json b/solid-link-mark-view/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-link-mark-view/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-link-mark-view/tsconfig.json b/solid-link-mark-view/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-link-mark-view/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-link-mark-view/tsconfig.node.json b/solid-link-mark-view/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-link-mark-view/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-link-mark-view/vite.config.ts b/solid-link-mark-view/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-link-mark-view/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-link/.gitignore b/solid-link/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-link/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-link/README.md b/solid-link/README.md new file mode 100644 index 0000000000..62a1edbb87 --- /dev/null +++ b/solid-link/README.md @@ -0,0 +1,15 @@ +# solid-link + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-link) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-link) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-link solid-link +cd solid-link +npm install +npm run dev +``` diff --git a/solid-link/index.html b/solid-link/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-link/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-link/package.json b/solid-link/package.json new file mode 100644 index 0000000000..5401c5c25f --- /dev/null +++ b/solid-link/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-link", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-link/src/App.tsx b/solid-link/src/App.tsx new file mode 100644 index 0000000000..1cf0f24636 --- /dev/null +++ b/solid-link/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/link' + +export default function App() { + return +} diff --git a/solid-link/src/app.css b/solid-link/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-link/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-link/src/components/editor/examples/link/editor.tsx b/solid-link/src/components/editor/examples/link/editor.tsx new file mode 100644 index 0000000000..feddf96214 --- /dev/null +++ b/solid-link/src/components/editor/examples/link/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-link' +import { InlineMenu } from '../../ui/inline-menu' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/solid-link/src/components/editor/examples/link/extension.ts b/solid-link/src/components/editor/examples/link/extension.ts new file mode 100644 index 0000000000..bf499147da --- /dev/null +++ b/solid-link/src/components/editor/examples/link/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLink } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-link/src/components/editor/examples/link/index.ts b/solid-link/src/components/editor/examples/link/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-link/src/components/editor/examples/link/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-link/src/components/editor/sample/sample-doc-link.ts b/solid-link/src/components/editor/sample/sample-doc-link.ts new file mode 100644 index 0000000000..726cf334fd --- /dev/null +++ b/solid-link/src/components/editor/sample/sample-doc-link.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is an ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/solid-link/src/components/editor/ui/button/button.tsx b/solid-link/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-link/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-link/src/components/editor/ui/button/index.ts b/solid-link/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-link/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-link/src/components/editor/ui/inline-menu/index.ts b/solid-link/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/solid-link/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/solid-link/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-link/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..d61df6d794 --- /dev/null +++ b/solid-link/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,233 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/solid' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/solid/inline-popover' +import { createSignal, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu(): JSX.Element { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor().commands.addLink({ href }) + } else { + editor().commands.removeLink() + } + + setLinkMenuOpen(false) + editor().focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + + + + {(item) => ( + setLinkMenuOpen(event.detail)} + > + + + +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+
+ + + +
+
+
+ )} +
+ + ) +} diff --git a/solid-link/src/index.tsx b/solid-link/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-link/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-link/tsconfig.app.json b/solid-link/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-link/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-link/tsconfig.json b/solid-link/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-link/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-link/tsconfig.node.json b/solid-link/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-link/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-link/vite.config.ts b/solid-link/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-link/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-list-custom-checkbox/.gitignore b/solid-list-custom-checkbox/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-list-custom-checkbox/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-list-custom-checkbox/README.md b/solid-list-custom-checkbox/README.md new file mode 100644 index 0000000000..919d9a0c4b --- /dev/null +++ b/solid-list-custom-checkbox/README.md @@ -0,0 +1,15 @@ +# solid-list-custom-checkbox + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-list-custom-checkbox) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-list-custom-checkbox) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-list-custom-checkbox solid-list-custom-checkbox +cd solid-list-custom-checkbox +npm install +npm run dev +``` diff --git a/solid-list-custom-checkbox/index.html b/solid-list-custom-checkbox/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-list-custom-checkbox/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-list-custom-checkbox/package.json b/solid-list-custom-checkbox/package.json new file mode 100644 index 0000000000..ef6bdd17fa --- /dev/null +++ b/solid-list-custom-checkbox/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-list-custom-checkbox", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-list-custom-checkbox/src/App.tsx b/solid-list-custom-checkbox/src/App.tsx new file mode 100644 index 0000000000..96b82e9a84 --- /dev/null +++ b/solid-list-custom-checkbox/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/list-custom-checkbox' + +export default function App() { + return +} diff --git a/solid-list-custom-checkbox/src/app.css b/solid-list-custom-checkbox/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-list-custom-checkbox/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css new file mode 100644 index 0000000000..ec631b72ad --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css @@ -0,0 +1,75 @@ +div[data-custom-list-css-enabled] + .ProseMirror + .prosemirror-flat-list[data-list-kind='task'] { + & > .list-marker label { + box-sizing: border-box; + display: flex; + position: relative; + left: calc(var(--spacing) * -0.5); + align-items: center; + cursor: pointer; + transition: transform 0.15s ease-in-out; + + &:hover { + transform: scale(1.1); + } + + &::after { + position: absolute; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + content: ''; + color: var(--color-white); + opacity: 0; + } + + /* https://api.iconify.design/lucide.css?icons=check */ + &::after { + display: inline-block; + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); + } + + & input { + box-sizing: border-box; + appearance: none; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + margin: 0; + border-width: 1px; + border-style: solid; + border-radius: var(--radius-md); + border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); + box-shadow: var(--shadow-sm); + cursor: pointer; + transition: all 0.15s ease-in-out; + + &:hover { + box-shadow: var(--shadow-md); + } + + &:checked { + border-color: var(--color-red-500); + background-color: var(--color-red-500); + } + } + } + + &[data-list-checked] > .list-marker label { + &::after { + opacity: 1; + } + } + + &[data-list-checked] { + color: var(--color-gray-400); + text-decoration: line-through; + text-decoration-color: var(--color-gray-400); + } +} diff --git a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx new file mode 100644 index 0000000000..a82283f280 --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.tsx @@ -0,0 +1,42 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import './custom-list.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-list-custom-checkbox' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ + extension, + defaultContent, + }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/solid-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts new file mode 100644 index 0000000000..972611aed1 --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts @@ -0,0 +1,38 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', + }, + { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, + { type: 'text', text: ' for the styles.' }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Completed Task' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Incomplete Task' }], + }, + ], + }, + ], +} diff --git a/solid-list-custom-checkbox/src/components/editor/ui/button/button.tsx b/solid-list-custom-checkbox/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-list-custom-checkbox/src/components/editor/ui/button/index.ts b/solid-list-custom-checkbox/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/solid-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx b/solid-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-list-custom-checkbox/src/index.tsx b/solid-list-custom-checkbox/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-list-custom-checkbox/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-list-custom-checkbox/tsconfig.app.json b/solid-list-custom-checkbox/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-list-custom-checkbox/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-list-custom-checkbox/tsconfig.json b/solid-list-custom-checkbox/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-list-custom-checkbox/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-list-custom-checkbox/tsconfig.node.json b/solid-list-custom-checkbox/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-list-custom-checkbox/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-list-custom-checkbox/vite.config.ts b/solid-list-custom-checkbox/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-list-custom-checkbox/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-list/.gitignore b/solid-list/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-list/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-list/README.md b/solid-list/README.md new file mode 100644 index 0000000000..8fcf0f8d9d --- /dev/null +++ b/solid-list/README.md @@ -0,0 +1,15 @@ +# solid-list + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-list) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-list) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-list solid-list +cd solid-list +npm install +npm run dev +``` diff --git a/solid-list/index.html b/solid-list/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-list/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-list/package.json b/solid-list/package.json new file mode 100644 index 0000000000..b6f03a420f --- /dev/null +++ b/solid-list/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-list", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-list/src/App.tsx b/solid-list/src/App.tsx new file mode 100644 index 0000000000..73f050ef0c --- /dev/null +++ b/solid-list/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/list' + +export default function App() { + return +} diff --git a/solid-list/src/app.css b/solid-list/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-list/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-list/src/components/editor/examples/list/editor.tsx b/solid-list/src/components/editor/examples/list/editor.tsx new file mode 100644 index 0000000000..c4874a51be --- /dev/null +++ b/solid-list/src/components/editor/examples/list/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-list' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-list/src/components/editor/examples/list/extension.ts b/solid-list/src/components/editor/examples/list/extension.ts new file mode 100644 index 0000000000..f66bae6ff7 --- /dev/null +++ b/solid-list/src/components/editor/examples/list/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineList } from 'prosekit/extensions/list' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineList(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-list/src/components/editor/examples/list/index.ts b/solid-list/src/components/editor/examples/list/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-list/src/components/editor/examples/list/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-list/src/components/editor/sample/sample-doc-list.ts b/solid-list/src/components/editor/sample/sample-doc-list.ts new file mode 100644 index 0000000000..091bc37185 --- /dev/null +++ b/solid-list/src/components/editor/sample/sample-doc-list.ts @@ -0,0 +1,47 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Ordered List' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'toggle', collapsed: true }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, + { + type: 'list', + attrs: { + kind: 'bullet', + }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, + ], + }, + ], + }, + ], +} diff --git a/solid-list/src/components/editor/ui/button/button.tsx b/solid-list/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-list/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-list/src/components/editor/ui/button/index.ts b/solid-list/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-list/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-list/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-list/src/components/editor/ui/image-upload-popover/index.ts b/solid-list/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-list/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-list/src/components/editor/ui/toolbar/index.ts b/solid-list/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-list/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-list/src/components/editor/ui/toolbar/toolbar.tsx b/solid-list/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-list/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-list/src/index.tsx b/solid-list/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-list/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-list/tsconfig.app.json b/solid-list/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-list/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-list/tsconfig.json b/solid-list/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-list/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-list/tsconfig.node.json b/solid-list/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-list/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-list/vite.config.ts b/solid-list/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-list/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-loro/.gitignore b/solid-loro/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-loro/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-loro/README.md b/solid-loro/README.md new file mode 100644 index 0000000000..b8f79c0da7 --- /dev/null +++ b/solid-loro/README.md @@ -0,0 +1,15 @@ +# solid-loro + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-loro) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-loro) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-loro solid-loro +cd solid-loro +npm install +npm run dev +``` diff --git a/solid-loro/index.html b/solid-loro/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-loro/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-loro/package.json b/solid-loro/package.json new file mode 100644 index 0000000000..32dff9f365 --- /dev/null +++ b/solid-loro/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-solid-loro", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "loro-crdt": "^1.12.1", + "loro-prosemirror": "^0.4.3", + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12", + "vite-plugin-wasm": "^3.6.0" + } +} diff --git a/solid-loro/src/App.tsx b/solid-loro/src/App.tsx new file mode 100644 index 0000000000..71d2a6b080 --- /dev/null +++ b/solid-loro/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/loro' + +export default function App() { + return +} diff --git a/solid-loro/src/app.css b/solid-loro/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-loro/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-loro/src/components/editor/examples/loro/editor-component.tsx b/solid-loro/src/components/editor/examples/loro/editor-component.tsx new file mode 100644 index 0000000000..bfcbe67370 --- /dev/null +++ b/solid-loro/src/components/editor/examples/loro/editor-component.tsx @@ -0,0 +1,34 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/loro/style.css' + +import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function EditorComponent(props: { + loro: LoroDocType + awareness: CursorAwareness +}): JSX.Element { + const extension = defineExtension(props.loro, props.awareness) + const editor = createEditor({ extension }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-loro/src/components/editor/examples/loro/editor.tsx b/solid-loro/src/components/editor/examples/loro/editor.tsx new file mode 100644 index 0000000000..f9f94e3b93 --- /dev/null +++ b/solid-loro/src/components/editor/examples/loro/editor.tsx @@ -0,0 +1,56 @@ +import { LoroDoc, type AwarenessListener } from 'loro-crdt' +import { CursorAwareness, type LoroDocType } from 'loro-prosemirror' +import { onCleanup, type JSX } from 'solid-js' + +import EditorComponent from './editor-component' + +export default function Editor(): JSX.Element { + const loroA: LoroDocType = new LoroDoc() + const loroB: LoroDocType = new LoroDoc() + + const idA = loroA.peerIdStr + const idB = loroB.peerIdStr + + const awarenessA = new CursorAwareness(idA) + const awarenessB = new CursorAwareness(idB) + + loroA.import(loroB.export({ mode: 'update' })) + loroB.import(loroA.export({ mode: 'update' })) + + const unsubscribeA = loroA.subscribeLocalUpdates((updates) => { + loroB.import(updates) + }) + + const unsubscribeB = loroB.subscribeLocalUpdates((updates) => { + loroA.import(updates) + }) + + const awarenessAListener: AwarenessListener = (_, origin) => { + if (origin === 'local') { + awarenessB.apply(awarenessA.encode([idA])) + } + } + + const awarenessBListener: AwarenessListener = (_, origin) => { + if (origin === 'local') { + awarenessA.apply(awarenessB.encode([idB])) + } + } + + awarenessA.addListener(awarenessAListener) + awarenessB.addListener(awarenessBListener) + + onCleanup(() => { + awarenessA.removeListener(awarenessAListener) + awarenessB.removeListener(awarenessBListener) + unsubscribeA() + unsubscribeB() + }) + + return ( +
+ + +
+ ) +} diff --git a/solid-loro/src/components/editor/examples/loro/extension.ts b/solid-loro/src/components/editor/examples/loro/extension.ts new file mode 100644 index 0000000000..5b2380c7c9 --- /dev/null +++ b/solid-loro/src/components/editor/examples/loro/extension.ts @@ -0,0 +1,47 @@ +import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineLoro } from 'prosekit/extensions/loro' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { + return union( + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineLoro({ doc, awareness }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-loro/src/components/editor/examples/loro/index.ts b/solid-loro/src/components/editor/examples/loro/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-loro/src/components/editor/examples/loro/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-loro/src/components/editor/ui/button/button.tsx b/solid-loro/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-loro/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-loro/src/components/editor/ui/button/index.ts b/solid-loro/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-loro/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-loro/src/components/editor/ui/image-upload-popover/index.ts b/solid-loro/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-loro/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-loro/src/components/editor/ui/toolbar/index.ts b/solid-loro/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-loro/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-loro/src/components/editor/ui/toolbar/toolbar.tsx b/solid-loro/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-loro/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-loro/src/index.tsx b/solid-loro/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-loro/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-loro/tsconfig.app.json b/solid-loro/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-loro/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-loro/tsconfig.json b/solid-loro/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-loro/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-loro/tsconfig.node.json b/solid-loro/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-loro/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-loro/vite.config.ts b/solid-loro/vite.config.ts new file mode 100644 index 0000000000..1987ce5dc6 --- /dev/null +++ b/solid-loro/vite.config.ts @@ -0,0 +1,8 @@ +import wasm from 'vite-plugin-wasm' +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [wasm(), solid(), tailwindcss()], +}) diff --git a/solid-mark-rule/.gitignore b/solid-mark-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-mark-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-mark-rule/README.md b/solid-mark-rule/README.md new file mode 100644 index 0000000000..74c0c98b4c --- /dev/null +++ b/solid-mark-rule/README.md @@ -0,0 +1,15 @@ +# solid-mark-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-mark-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-mark-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-mark-rule solid-mark-rule +cd solid-mark-rule +npm install +npm run dev +``` diff --git a/solid-mark-rule/index.html b/solid-mark-rule/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-mark-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-mark-rule/package.json b/solid-mark-rule/package.json new file mode 100644 index 0000000000..535f0d5adb --- /dev/null +++ b/solid-mark-rule/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-mark-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-mark-rule/src/App.tsx b/solid-mark-rule/src/App.tsx new file mode 100644 index 0000000000..4e93a4bf60 --- /dev/null +++ b/solid-mark-rule/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/mark-rule' + +export default function App() { + return +} diff --git a/solid-mark-rule/src/app.css b/solid-mark-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-mark-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-mark-rule/src/components/editor/examples/mark-rule/editor.tsx b/solid-mark-rule/src/components/editor/examples/mark-rule/editor.tsx new file mode 100644 index 0000000000..6f695978e8 --- /dev/null +++ b/solid-mark-rule/src/components/editor/examples/mark-rule/editor.tsx @@ -0,0 +1,26 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { defineExtension } from './extension' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/solid-mark-rule/src/components/editor/examples/mark-rule/extension.ts new file mode 100644 index 0000000000..4a1de40783 --- /dev/null +++ b/solid-mark-rule/src/components/editor/examples/mark-rule/extension.ts @@ -0,0 +1,32 @@ +import { + defineBaseCommands, + defineBaseKeymap, + defineHistory, + union, +} from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { definePlaceholder } from 'prosekit/extensions/placeholder' +import { defineText } from 'prosekit/extensions/text' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +import { defineIssueLink } from './issue-link' + +export function defineExtension() { + return union( + defineDoc(), + defineText(), + defineParagraph(), + defineHistory(), + defineBaseKeymap(), + defineBaseCommands(), + defineVirtualSelection(), + defineLinkSpec(), + defineLinkMarkRule(), + definePlaceholder({ placeholder: 'Try typing #123' }), + defineIssueLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-mark-rule/src/components/editor/examples/mark-rule/index.ts b/solid-mark-rule/src/components/editor/examples/mark-rule/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-mark-rule/src/components/editor/examples/mark-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/solid-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts new file mode 100644 index 0000000000..3840b5e53d --- /dev/null +++ b/solid-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts @@ -0,0 +1,32 @@ +import { defineMarkSpec, union } from 'prosekit/core' +import { defineMarkRule } from 'prosekit/extensions/mark-rule' + +export function defineIssueLink() { + return union( + defineMarkSpec({ + name: 'issueLink', + inclusive: false, + attrs: { + issueNumber: {}, + }, + toDOM(node) { + const issueNumber = node.attrs.issueNumber as number + return [ + 'a', + { + href: `https://example.com/issues/${issueNumber}`, + title: `Issue #${issueNumber}`, + }, + 0, + ] + }, + }), + defineMarkRule({ + regex: /#(\d+)/g, + type: 'issueLink', + attrs: (match) => { + return { issueNumber: Number.parseInt(match[1] || '0') } + }, + }), + ) +} diff --git a/solid-mark-rule/src/index.tsx b/solid-mark-rule/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-mark-rule/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-mark-rule/tsconfig.app.json b/solid-mark-rule/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-mark-rule/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-mark-rule/tsconfig.json b/solid-mark-rule/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-mark-rule/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-mark-rule/tsconfig.node.json b/solid-mark-rule/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-mark-rule/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-mark-rule/vite.config.ts b/solid-mark-rule/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-mark-rule/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-minimal/.gitignore b/solid-minimal/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-minimal/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-minimal/README.md b/solid-minimal/README.md new file mode 100644 index 0000000000..a4caabd2bb --- /dev/null +++ b/solid-minimal/README.md @@ -0,0 +1,15 @@ +# solid-minimal + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-minimal) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-minimal) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-minimal solid-minimal +cd solid-minimal +npm install +npm run dev +``` diff --git a/solid-minimal/index.html b/solid-minimal/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-minimal/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-minimal/package.json b/solid-minimal/package.json new file mode 100644 index 0000000000..94b62599a7 --- /dev/null +++ b/solid-minimal/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-minimal/src/App.tsx b/solid-minimal/src/App.tsx new file mode 100644 index 0000000000..523aea224a --- /dev/null +++ b/solid-minimal/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/minimal' + +export default function App() { + return +} diff --git a/solid-minimal/src/app.css b/solid-minimal/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-minimal/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-minimal/src/components/editor/examples/minimal/editor.tsx b/solid-minimal/src/components/editor/examples/minimal/editor.tsx new file mode 100644 index 0000000000..eef69dfca1 --- /dev/null +++ b/solid-minimal/src/components/editor/examples/minimal/editor.tsx @@ -0,0 +1,18 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +export default function Editor(): JSX.Element { + const extension = defineBasicExtension() + const editor = createEditor({ extension }) + + return ( + +
+
+ ) +} diff --git a/solid-minimal/src/components/editor/examples/minimal/index.ts b/solid-minimal/src/components/editor/examples/minimal/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-minimal/src/components/editor/examples/minimal/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-minimal/src/index.tsx b/solid-minimal/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-minimal/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-minimal/tsconfig.app.json b/solid-minimal/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-minimal/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-minimal/tsconfig.json b/solid-minimal/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-minimal/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-minimal/tsconfig.node.json b/solid-minimal/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-minimal/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-minimal/vite.config.ts b/solid-minimal/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-minimal/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-placeholder/.gitignore b/solid-placeholder/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-placeholder/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-placeholder/README.md b/solid-placeholder/README.md new file mode 100644 index 0000000000..2686f67d40 --- /dev/null +++ b/solid-placeholder/README.md @@ -0,0 +1,15 @@ +# solid-placeholder + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-placeholder) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-placeholder) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-placeholder solid-placeholder +cd solid-placeholder +npm install +npm run dev +``` diff --git a/solid-placeholder/index.html b/solid-placeholder/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-placeholder/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-placeholder/package.json b/solid-placeholder/package.json new file mode 100644 index 0000000000..575ceb9bad --- /dev/null +++ b/solid-placeholder/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-placeholder", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-placeholder/src/App.tsx b/solid-placeholder/src/App.tsx new file mode 100644 index 0000000000..919da8503a --- /dev/null +++ b/solid-placeholder/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/placeholder' + +export default function App() { + return +} diff --git a/solid-placeholder/src/app.css b/solid-placeholder/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-placeholder/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-placeholder/src/components/editor/examples/placeholder/editor.tsx b/solid-placeholder/src/components/editor/examples/placeholder/editor.tsx new file mode 100644 index 0000000000..e759ced14a --- /dev/null +++ b/solid-placeholder/src/components/editor/examples/placeholder/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, jsonFromNode, type NodeJSON } from 'prosekit/core' +import type { ProseMirrorNode } from 'prosekit/pm/model' +import { ProseKit, useDocChange } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { defineExtension } from './extension' + +export default function Editor(props: { + initialContent?: NodeJSON + onDocUpdate?: (doc: NodeJSON) => void +}): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ + extension, + defaultContent: props.initialContent, + }) + + const handleDocChange = (doc: ProseMirrorNode) => + props.onDocUpdate?.(jsonFromNode(doc)) + useDocChange(handleDocChange, { editor }) + + return ( + +
+
+
+
+
+
+ ) +} diff --git a/solid-placeholder/src/components/editor/examples/placeholder/extension.ts b/solid-placeholder/src/components/editor/examples/placeholder/extension.ts new file mode 100644 index 0000000000..12d0ba26f4 --- /dev/null +++ b/solid-placeholder/src/components/editor/examples/placeholder/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Type something...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-placeholder/src/components/editor/examples/placeholder/index.ts b/solid-placeholder/src/components/editor/examples/placeholder/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-placeholder/src/components/editor/examples/placeholder/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-placeholder/src/index.tsx b/solid-placeholder/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-placeholder/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-placeholder/tsconfig.app.json b/solid-placeholder/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-placeholder/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-placeholder/tsconfig.json b/solid-placeholder/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-placeholder/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-placeholder/tsconfig.node.json b/solid-placeholder/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-placeholder/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-placeholder/vite.config.ts b/solid-placeholder/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-placeholder/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-readonly/.gitignore b/solid-readonly/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-readonly/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-readonly/README.md b/solid-readonly/README.md new file mode 100644 index 0000000000..1dadf55d5d --- /dev/null +++ b/solid-readonly/README.md @@ -0,0 +1,15 @@ +# solid-readonly + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-readonly) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-readonly) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-readonly solid-readonly +cd solid-readonly +npm install +npm run dev +``` diff --git a/solid-readonly/index.html b/solid-readonly/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-readonly/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-readonly/package.json b/solid-readonly/package.json new file mode 100644 index 0000000000..f031483b7c --- /dev/null +++ b/solid-readonly/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-readonly", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-readonly/src/App.tsx b/solid-readonly/src/App.tsx new file mode 100644 index 0000000000..dc728e840f --- /dev/null +++ b/solid-readonly/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/readonly' + +export default function App() { + return +} diff --git a/solid-readonly/src/app.css b/solid-readonly/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-readonly/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-readonly/src/components/editor/examples/readonly/editor.tsx b/solid-readonly/src/components/editor/examples/readonly/editor.tsx new file mode 100644 index 0000000000..0752dfca2d --- /dev/null +++ b/solid-readonly/src/components/editor/examples/readonly/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-readonly' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-readonly/src/components/editor/examples/readonly/extension.ts b/solid-readonly/src/components/editor/examples/readonly/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/solid-readonly/src/components/editor/examples/readonly/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/solid-readonly/src/components/editor/examples/readonly/index.ts b/solid-readonly/src/components/editor/examples/readonly/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-readonly/src/components/editor/examples/readonly/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-readonly/src/components/editor/examples/readonly/toolbar.tsx b/solid-readonly/src/components/editor/examples/readonly/toolbar.tsx new file mode 100644 index 0000000000..0184e5c77f --- /dev/null +++ b/solid-readonly/src/components/editor/examples/readonly/toolbar.tsx @@ -0,0 +1,21 @@ +import type { JSX } from 'solid-js' + +import { Button } from '../../ui/button' + +import { useReadonly } from './use-readonly' + +export default function Toolbar(): JSX.Element { + const { readonly, setReadonly } = useReadonly() + + return ( +
+ + + +
+ ) +} diff --git a/solid-readonly/src/components/editor/examples/readonly/use-readonly.ts b/solid-readonly/src/components/editor/examples/readonly/use-readonly.ts new file mode 100644 index 0000000000..3aea61f0bb --- /dev/null +++ b/solid-readonly/src/components/editor/examples/readonly/use-readonly.ts @@ -0,0 +1,14 @@ +import { defineReadonly } from 'prosekit/extensions/readonly' +import { useExtension } from 'prosekit/solid' +import { createMemo, createSignal } from 'solid-js' + +export function useReadonly() { + const [readonly, setReadonly] = createSignal(true) + + const extension = createMemo(() => { + return readonly() ? defineReadonly() : null + }) + useExtension(extension) + + return { readonly, setReadonly } +} diff --git a/solid-readonly/src/components/editor/sample/sample-doc-readonly.ts b/solid-readonly/src/components/editor/sample/sample-doc-readonly.ts new file mode 100644 index 0000000000..abd9e2c6ac --- /dev/null +++ b/solid-readonly/src/components/editor/sample/sample-doc-readonly.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', + }, + ], + }, + ], +} diff --git a/solid-readonly/src/components/editor/ui/button/button.tsx b/solid-readonly/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-readonly/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-readonly/src/components/editor/ui/button/index.ts b/solid-readonly/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-readonly/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-readonly/src/index.tsx b/solid-readonly/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-readonly/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-readonly/tsconfig.app.json b/solid-readonly/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-readonly/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-readonly/tsconfig.json b/solid-readonly/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-readonly/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-readonly/tsconfig.node.json b/solid-readonly/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-readonly/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-readonly/vite.config.ts b/solid-readonly/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-readonly/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-rtl/.gitignore b/solid-rtl/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-rtl/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-rtl/README.md b/solid-rtl/README.md new file mode 100644 index 0000000000..467a5010fb --- /dev/null +++ b/solid-rtl/README.md @@ -0,0 +1,15 @@ +# solid-rtl + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-rtl) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-rtl) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-rtl solid-rtl +cd solid-rtl +npm install +npm run dev +``` diff --git a/solid-rtl/index.html b/solid-rtl/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-rtl/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-rtl/package.json b/solid-rtl/package.json new file mode 100644 index 0000000000..16eaf1e341 --- /dev/null +++ b/solid-rtl/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-rtl", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-rtl/src/App.tsx b/solid-rtl/src/App.tsx new file mode 100644 index 0000000000..b7c8653ece --- /dev/null +++ b/solid-rtl/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/rtl' + +export default function App() { + return +} diff --git a/solid-rtl/src/app.css b/solid-rtl/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-rtl/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-rtl/src/components/editor/examples/rtl/editor.tsx b/solid-rtl/src/components/editor/examples/rtl/editor.tsx new file mode 100644 index 0000000000..98f5b62503 --- /dev/null +++ b/solid-rtl/src/components/editor/examples/rtl/editor.tsx @@ -0,0 +1,48 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-rtl' +import { sampleUploader } from '../../sample/sample-uploader' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' +import { InlineMenu } from '../../ui/inline-menu' +import { SlashMenu } from '../../ui/slash-menu' +import { TableHandle } from '../../ui/table-handle' +import { Toolbar } from '../../ui/toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const extension = defineBasicExtension() + const defaultContent = props.initialContent ?? sampleContent + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+ + + + + +
+
+
+ ) +} diff --git a/solid-rtl/src/components/editor/examples/rtl/index.ts b/solid-rtl/src/components/editor/examples/rtl/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-rtl/src/components/editor/examples/rtl/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-rtl/src/components/editor/sample/sample-doc-rtl.ts b/solid-rtl/src/components/editor/sample/sample-doc-rtl.ts new file mode 100644 index 0000000000..696e797724 --- /dev/null +++ b/solid-rtl/src/components/editor/sample/sample-doc-rtl.ts @@ -0,0 +1,187 @@ +import type { NodeJSON } from 'prosekit/core' + +const translation = { + Paragraph: 'فقرة', + 'Root list item': 'عنصر قائمة جذري', + 'Sub list item': 'عنصر قائمة فرعي', + 'Completed task': 'مهمة مكتملة', + 'Pending task': 'مهمة قيد الانتظار', + Quote: 'اقتباس', +} as const + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Right to Left' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Paragraph'] }], + }, + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Root list item'] }], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Completed task'] }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Pending task'] }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: 'hello world', + }, + ], + }, + + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, + ], + }, + ], + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: translation['Quote'], + }, + ], + }, + ], + }, + ], +} diff --git a/solid-rtl/src/components/editor/sample/sample-uploader.ts b/solid-rtl/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/solid-rtl/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/solid-rtl/src/components/editor/ui/block-handle/block-handle.tsx b/solid-rtl/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..95e1693ef6 --- /dev/null +++ b/solid-rtl/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,32 @@ +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/solid/block-handle' +import type { JSX } from 'solid-js' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props): JSX.Element { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/solid-rtl/src/components/editor/ui/block-handle/index.ts b/solid-rtl/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/solid-rtl/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/solid-rtl/src/components/editor/ui/button/button.tsx b/solid-rtl/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-rtl/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-rtl/src/components/editor/ui/button/index.ts b/solid-rtl/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-rtl/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/solid-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx new file mode 100644 index 0000000000..c5a24c7faa --- /dev/null +++ b/solid-rtl/src/components/editor/ui/drop-indicator/drop-indicator.tsx @@ -0,0 +1,6 @@ +import { DropIndicator as BaseDropIndicator } from 'prosekit/solid/drop-indicator' +import type { JSX } from 'solid-js' + +export default function DropIndicator(): JSX.Element { + return +} diff --git a/solid-rtl/src/components/editor/ui/drop-indicator/index.ts b/solid-rtl/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..f8fb7139c4 --- /dev/null +++ b/solid-rtl/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator' diff --git a/solid-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-rtl/src/components/editor/ui/image-upload-popover/index.ts b/solid-rtl/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-rtl/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-rtl/src/components/editor/ui/inline-menu/index.ts b/solid-rtl/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/solid-rtl/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/solid-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..d61df6d794 --- /dev/null +++ b/solid-rtl/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,233 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/solid' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/solid/inline-popover' +import { createSignal, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu(): JSX.Element { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor().commands.addLink({ href }) + } else { + editor().commands.removeLink() + } + + setLinkMenuOpen(false) + editor().focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + + + + {(item) => ( + setLinkMenuOpen(event.detail)} + > + + + +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+
+ + + +
+
+
+ )} +
+ + ) +} diff --git a/solid-rtl/src/components/editor/ui/slash-menu/index.ts b/solid-rtl/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/solid-rtl/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..aae5f3dc6b --- /dev/null +++ b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,10 @@ +import { AutocompleteEmpty } from 'prosekit/solid/autocomplete' +import type { JSX } from 'solid-js' + +export default function SlashMenuEmpty(): JSX.Element { + return ( + + No results + + ) +} diff --git a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..9d8101d019 --- /dev/null +++ b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,22 @@ +import { AutocompleteItem } from 'prosekit/solid/autocomplete' +import { Show, type JSX } from 'solid-js' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}): JSX.Element { + return ( + + {props.label} + + + {props.kbd} + + + + ) +} diff --git a/solid-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..c7090d7f36 --- /dev/null +++ b/solid-rtl/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,101 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/solid' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/solid/autocomplete' +import type { JSX } from 'solid-js' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor().commands.setParagraph()} + /> + + editor().commands.setHeading({ level: 1 })} + /> + + editor().commands.setHeading({ level: 2 })} + /> + + editor().commands.setHeading({ level: 3 })} + /> + + editor().commands.wrapInList({ kind: 'bullet' })} + /> + + editor().commands.wrapInList({ kind: 'ordered' })} + /> + + editor().commands.wrapInList({ kind: 'task' })} + /> + + editor().commands.wrapInList({ kind: 'toggle' })} + /> + + editor().commands.setBlockquote()} + /> + + editor().commands.insertTable({ row: 3, col: 3 })} + /> + + editor().commands.insertHorizontalRule()} + /> + + editor().commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/solid-rtl/src/components/editor/ui/table-handle/index.ts b/solid-rtl/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/solid-rtl/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/solid-rtl/src/components/editor/ui/table-handle/table-handle.tsx b/solid-rtl/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..463f4d3657 --- /dev/null +++ b/solid-rtl/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,187 @@ +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/solid' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/solid/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/solid/table-handle' +import { Show, type JSX } from 'solid-js' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props): JSX.Element { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + + state().addTableColumnBefore.command()} + > + Insert Left + + + + state().addTableColumnAfter.command()} + > + Insert Right + + + + state().deleteCellSelection.command()} + > + Clear Contents + + Del + + + + + state().deleteTableColumn.command()} + > + Delete Column + + + + state().deleteTable.command()} + > + Delete Table + + + + +
+
+
+ + + + +
+
+ + + + state().addTableRowAbove.command()} + > + Insert Above + + + + state().addTableRowBelow.command()} + > + Insert Below + + + + state().deleteCellSelection.command()} + > + Clear Contents + + Del + + + + + state().deleteTableRow.command()} + > + Delete Row + + + + state().deleteTable.command()} + > + Delete Table + + + + +
+
+
+
+ ) +} diff --git a/solid-rtl/src/components/editor/ui/toolbar/index.ts b/solid-rtl/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-rtl/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-rtl/src/components/editor/ui/toolbar/toolbar.tsx b/solid-rtl/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-rtl/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-rtl/src/index.tsx b/solid-rtl/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-rtl/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-rtl/tsconfig.app.json b/solid-rtl/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-rtl/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-rtl/tsconfig.json b/solid-rtl/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-rtl/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-rtl/tsconfig.node.json b/solid-rtl/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-rtl/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-rtl/vite.config.ts b/solid-rtl/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-rtl/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-save-html/.gitignore b/solid-save-html/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-save-html/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-save-html/README.md b/solid-save-html/README.md new file mode 100644 index 0000000000..cf82df568e --- /dev/null +++ b/solid-save-html/README.md @@ -0,0 +1,15 @@ +# solid-save-html + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-save-html) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-save-html) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-save-html solid-save-html +cd solid-save-html +npm install +npm run dev +``` diff --git a/solid-save-html/index.html b/solid-save-html/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-save-html/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-save-html/package.json b/solid-save-html/package.json new file mode 100644 index 0000000000..b5ac06d34a --- /dev/null +++ b/solid-save-html/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-save-html", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-save-html/src/App.tsx b/solid-save-html/src/App.tsx new file mode 100644 index 0000000000..cd1a678bb6 --- /dev/null +++ b/solid-save-html/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-html' + +export default function App() { + return +} diff --git a/solid-save-html/src/app.css b/solid-save-html/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-save-html/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-save-html/src/components/editor/examples/save-html/editor.tsx b/solid-save-html/src/components/editor/examples/save-html/editor.tsx new file mode 100644 index 0000000000..8a6c1886b1 --- /dev/null +++ b/solid-save-html/src/components/editor/examples/save-html/editor.tsx @@ -0,0 +1,66 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, jsonFromHTML } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/solid' +import { createSignal, For, type JSX } from 'solid-js' + +export default function Editor(): JSX.Element { + const [records, setRecords] = createSignal([]) + const [hasUnsavedChange, setHasUnsavedChange] = createSignal(false) + + const extension = defineBasicExtension() + const editor = createEditor({ extension }) + + const handleDocChange = () => setHasUnsavedChange(true) + useDocChange(handleDocChange, { editor }) + + const handleSave = () => { + const record = editor.getDocHTML() + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + } + + const handleLoad = (record: string) => { + editor.setContent(jsonFromHTML(record, { schema: editor.schema })) + setHasUnsavedChange(false) + } + + return ( +
+ +
    + + {(record) => ( +
  • + + +
    {record}
    +
    +
  • + )} +
    +
+ +
+
+
+
+
+ ) +} diff --git a/solid-save-html/src/components/editor/examples/save-html/index.ts b/solid-save-html/src/components/editor/examples/save-html/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-save-html/src/components/editor/examples/save-html/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-save-html/src/index.tsx b/solid-save-html/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-save-html/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-save-html/tsconfig.app.json b/solid-save-html/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-save-html/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-save-html/tsconfig.json b/solid-save-html/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-save-html/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-save-html/tsconfig.node.json b/solid-save-html/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-save-html/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-save-html/vite.config.ts b/solid-save-html/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-save-html/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-save-json/.gitignore b/solid-save-json/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-save-json/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-save-json/README.md b/solid-save-json/README.md new file mode 100644 index 0000000000..335ce26bb9 --- /dev/null +++ b/solid-save-json/README.md @@ -0,0 +1,15 @@ +# solid-save-json + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-save-json) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-save-json) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-save-json solid-save-json +cd solid-save-json +npm install +npm run dev +``` diff --git a/solid-save-json/index.html b/solid-save-json/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-save-json/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-save-json/package.json b/solid-save-json/package.json new file mode 100644 index 0000000000..e6ccd98d46 --- /dev/null +++ b/solid-save-json/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-save-json", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-save-json/src/App.tsx b/solid-save-json/src/App.tsx new file mode 100644 index 0000000000..c35583f0b4 --- /dev/null +++ b/solid-save-json/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-json' + +export default function App() { + return +} diff --git a/solid-save-json/src/app.css b/solid-save-json/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-save-json/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-save-json/src/components/editor/examples/save-json/editor.tsx b/solid-save-json/src/components/editor/examples/save-json/editor.tsx new file mode 100644 index 0000000000..4b31002153 --- /dev/null +++ b/solid-save-json/src/components/editor/examples/save-json/editor.tsx @@ -0,0 +1,66 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/solid' +import { createSignal, For, type JSX } from 'solid-js' + +export default function Editor(): JSX.Element { + const [records, setRecords] = createSignal([]) + const [hasUnsavedChange, setHasUnsavedChange] = createSignal(false) + + const extension = defineBasicExtension() + const editor = createEditor({ extension }) + + const handleDocChange = () => setHasUnsavedChange(true) + useDocChange(handleDocChange, { editor }) + + const handleSave = () => { + const record = JSON.stringify(editor.getDocJSON()) + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + } + + const handleLoad = (record: string) => { + editor.setContent(JSON.parse(record) as NodeJSON) + setHasUnsavedChange(false) + } + + return ( +
+ +
    + + {(record) => ( +
  • + + +
    {record}
    +
    +
  • + )} +
    +
+ +
+
+
+
+
+ ) +} diff --git a/solid-save-json/src/components/editor/examples/save-json/index.ts b/solid-save-json/src/components/editor/examples/save-json/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-save-json/src/components/editor/examples/save-json/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-save-json/src/index.tsx b/solid-save-json/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-save-json/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-save-json/tsconfig.app.json b/solid-save-json/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-save-json/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-save-json/tsconfig.json b/solid-save-json/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-save-json/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-save-json/tsconfig.node.json b/solid-save-json/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-save-json/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-save-json/vite.config.ts b/solid-save-json/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-save-json/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-save-markdown/.gitignore b/solid-save-markdown/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-save-markdown/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-save-markdown/README.md b/solid-save-markdown/README.md new file mode 100644 index 0000000000..88666ea568 --- /dev/null +++ b/solid-save-markdown/README.md @@ -0,0 +1,15 @@ +# solid-save-markdown + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-save-markdown) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-save-markdown) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-save-markdown solid-save-markdown +cd solid-save-markdown +npm install +npm run dev +``` diff --git a/solid-save-markdown/index.html b/solid-save-markdown/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-save-markdown/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-save-markdown/package.json b/solid-save-markdown/package.json new file mode 100644 index 0000000000..5543b5a1fb --- /dev/null +++ b/solid-save-markdown/package.json @@ -0,0 +1,32 @@ +{ + "name": "example-solid-save-markdown", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "rehype-parse": "^9.0.1", + "rehype-remark": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-html": "^16.0.1", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "solid-js": "^1.9.13", + "unified": "^11.0.5" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-save-markdown/src/App.tsx b/solid-save-markdown/src/App.tsx new file mode 100644 index 0000000000..776d1fdf5b --- /dev/null +++ b/solid-save-markdown/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/save-markdown' + +export default function App() { + return +} diff --git a/solid-save-markdown/src/app.css b/solid-save-markdown/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-save-markdown/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-save-markdown/src/components/editor/examples/save-markdown/editor.tsx b/solid-save-markdown/src/components/editor/examples/save-markdown/editor.tsx new file mode 100644 index 0000000000..03452c522f --- /dev/null +++ b/solid-save-markdown/src/components/editor/examples/save-markdown/editor.tsx @@ -0,0 +1,70 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor, jsonFromHTML } from 'prosekit/core' +import { ProseKit, useDocChange } from 'prosekit/solid' +import { createSignal, For, type JSX } from 'solid-js' + +import { htmlFromMarkdown, markdownFromHTML } from './markdown' + +export default function Editor(): JSX.Element { + const [records, setRecords] = createSignal([]) + const [hasUnsavedChange, setHasUnsavedChange] = createSignal(false) + + const extension = defineBasicExtension() + const editor = createEditor({ extension }) + + const handleDocChange = () => setHasUnsavedChange(true) + useDocChange(handleDocChange, { editor }) + + const handleSave = () => { + const html = editor.getDocHTML() + const record = markdownFromHTML(html) + setRecords((prev) => [...prev, record]) + setHasUnsavedChange(false) + } + + const handleLoad = (record: string) => { + const html = htmlFromMarkdown(record) + editor.setContent(jsonFromHTML(html, { schema: editor.schema })) + setHasUnsavedChange(false) + } + + return ( +
+ +
    + + {(record) => ( +
  • + + +
    {record}
    +
    +
  • + )} +
    +
+ +
+
+
+
+
+ ) +} diff --git a/solid-save-markdown/src/components/editor/examples/save-markdown/index.ts b/solid-save-markdown/src/components/editor/examples/save-markdown/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-save-markdown/src/components/editor/examples/save-markdown/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/solid-save-markdown/src/components/editor/examples/save-markdown/markdown.ts new file mode 100644 index 0000000000..3f930adad2 --- /dev/null +++ b/solid-save-markdown/src/components/editor/examples/save-markdown/markdown.ts @@ -0,0 +1,26 @@ +import rehypeParse from 'rehype-parse' +import rehypeRemark from 'rehype-remark' +import remarkGfm from 'remark-gfm' +import remarkHtml from 'remark-html' +import remarkParse from 'remark-parse' +import remarkStringify from 'remark-stringify' +import { unified } from 'unified' + +export function markdownFromHTML(html: string): string { + return unified() + .use(rehypeParse) + .use(rehypeRemark) + .use(remarkGfm) + .use(remarkStringify) + .processSync(html) + .toString() +} + +export function htmlFromMarkdown(markdown: string): string { + return unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkHtml) + .processSync(markdown) + .toString() +} diff --git a/solid-save-markdown/src/index.tsx b/solid-save-markdown/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-save-markdown/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-save-markdown/tsconfig.app.json b/solid-save-markdown/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-save-markdown/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-save-markdown/tsconfig.json b/solid-save-markdown/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-save-markdown/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-save-markdown/tsconfig.node.json b/solid-save-markdown/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-save-markdown/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-save-markdown/vite.config.ts b/solid-save-markdown/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-save-markdown/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-search/.gitignore b/solid-search/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-search/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-search/README.md b/solid-search/README.md new file mode 100644 index 0000000000..dcd1c03410 --- /dev/null +++ b/solid-search/README.md @@ -0,0 +1,15 @@ +# solid-search + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-search) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-search) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-search solid-search +cd solid-search +npm install +npm run dev +``` diff --git a/solid-search/index.html b/solid-search/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-search/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-search/package.json b/solid-search/package.json new file mode 100644 index 0000000000..e45c16784d --- /dev/null +++ b/solid-search/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-search", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-search/src/App.tsx b/solid-search/src/App.tsx new file mode 100644 index 0000000000..2f6b77056f --- /dev/null +++ b/solid-search/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/search' + +export default function App() { + return +} diff --git a/solid-search/src/app.css b/solid-search/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-search/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-search/src/components/editor/examples/search/editor.tsx b/solid-search/src/components/editor/examples/search/editor.tsx new file mode 100644 index 0000000000..1aef7fcdd6 --- /dev/null +++ b/solid-search/src/components/editor/examples/search/editor.tsx @@ -0,0 +1,39 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/search/style.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-search' +import { Search } from '../../ui/search' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ + extension, + defaultContent, + }) + + return ( + +
+
+ +
+
+
+
+ ) +} diff --git a/solid-search/src/components/editor/examples/search/extension.ts b/solid-search/src/components/editor/examples/search/extension.ts new file mode 100644 index 0000000000..10ff13f614 --- /dev/null +++ b/solid-search/src/components/editor/examples/search/extension.ts @@ -0,0 +1,9 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineSearchCommands } from 'prosekit/extensions/search' + +export function defineExtension() { + return union(defineBasicExtension(), defineSearchCommands()) +} + +export type EditorExtension = ReturnType diff --git a/solid-search/src/components/editor/examples/search/index.ts b/solid-search/src/components/editor/examples/search/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-search/src/components/editor/examples/search/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-search/src/components/editor/sample/sample-doc-search.ts b/solid-search/src/components/editor/sample/sample-doc-search.ts new file mode 100644 index 0000000000..c8160cca2a --- /dev/null +++ b/solid-search/src/components/editor/sample/sample-doc-search.ts @@ -0,0 +1,79 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Baa, baa, black sheep,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Have you any wool?', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Yes, sir, yes, sir,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Three bags full;', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'One for the master,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the dame,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the little boy', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Who lives down the lane.', + }, + ], + }, + ], +} diff --git a/solid-search/src/components/editor/ui/button/button.tsx b/solid-search/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-search/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-search/src/components/editor/ui/button/index.ts b/solid-search/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-search/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-search/src/components/editor/ui/search/index.ts b/solid-search/src/components/editor/ui/search/index.ts new file mode 100644 index 0000000000..0a1f03c720 --- /dev/null +++ b/solid-search/src/components/editor/ui/search/index.ts @@ -0,0 +1 @@ +export { default as Search } from './search' diff --git a/solid-search/src/components/editor/ui/search/search.tsx b/solid-search/src/components/editor/ui/search/search.tsx new file mode 100644 index 0000000000..30ac5d0cfd --- /dev/null +++ b/solid-search/src/components/editor/ui/search/search.tsx @@ -0,0 +1,170 @@ +import { + defineSearchQuery, + type SearchCommandsExtension, +} from 'prosekit/extensions/search' +import { useEditor, useExtension } from 'prosekit/solid' +import { createMemo, createSignal, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function Search(props: { onClose?: VoidFunction }): JSX.Element { + const [showReplace, setShowReplace] = createSignal(false) + const toggleReplace = () => setShowReplace((value) => !value) + + const [searchText, setSearchText] = createSignal('') + const [replaceText, setReplaceText] = createSignal('') + const [caseSensitive, setCaseSensitive] = createSignal(false) + const [wholeWord, setWholeWord] = createSignal(false) + const [regexp, setRegexp] = createSignal(false) + const [literal, setLiteral] = createSignal(false) + + const extension = createMemo(() => { + if (!searchText()) { + return null + } + return defineSearchQuery({ + search: searchText(), + replace: replaceText(), + caseSensitive: caseSensitive(), + wholeWord: wholeWord(), + regexp: regexp(), + literal: literal(), + }) + }) + + useExtension(extension) + + const editor = useEditor() + + const handleSearchKeyDown = (event: KeyboardEvent) => { + if (isEnter(event)) { + event.preventDefault() + editor().commands.findNext() + } else if (isShiftEnter(event)) { + event.preventDefault() + editor().commands.findPrev() + } + } + + const handleReplaceKeyDown = (event: KeyboardEvent) => { + if (isEnter(event)) { + event.preventDefault() + editor().commands.replaceNext() + } else if (isShiftEnter(event)) { + event.preventDefault() + editor().commands.replaceAll() + } + } + + return ( +
+ + setSearchText(event.currentTarget.value)} + onKeyDown={handleSearchKeyDown} + class="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" + /> +
+ + + + + + + +
+ {showReplace() && ( + setReplaceText(event.currentTarget.value)} + onKeyDown={handleReplaceKeyDown} + class="flex h-9 rounded-md w-full bg-[canvas] px-3 py-2 text-sm placeholder:text-gray-500 dark:placeholder:text-gray-500 transition border box-border border-gray-200 dark:border-gray-800 border-solid ring-0 ring-transparent focus-visible:ring-2 focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 focus-visible:ring-offset-0 outline-hidden focus-visible:outline-hidden file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:cursor-not-allowed disabled:opacity-50 col-start-2" + /> + )} + {showReplace() && ( +
+ + +
+ )} +
+ ) +} + +function isEnter(event: KeyboardEvent) { + return ( + event.key === 'Enter' && + !event.shiftKey && + !event.metaKey && + !event.altKey && + !event.ctrlKey && + !event.isComposing + ) +} + +function isShiftEnter(event: KeyboardEvent) { + return ( + event.key === 'Enter' && + event.shiftKey && + !event.metaKey && + !event.altKey && + !event.ctrlKey && + !event.isComposing + ) +} diff --git a/solid-search/src/index.tsx b/solid-search/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-search/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-search/tsconfig.app.json b/solid-search/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-search/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-search/tsconfig.json b/solid-search/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-search/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-search/tsconfig.node.json b/solid-search/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-search/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-search/vite.config.ts b/solid-search/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-search/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-slash-menu/.gitignore b/solid-slash-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-slash-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-slash-menu/README.md b/solid-slash-menu/README.md new file mode 100644 index 0000000000..2745cf76bb --- /dev/null +++ b/solid-slash-menu/README.md @@ -0,0 +1,15 @@ +# solid-slash-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-slash-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-slash-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-slash-menu solid-slash-menu +cd solid-slash-menu +npm install +npm run dev +``` diff --git a/solid-slash-menu/index.html b/solid-slash-menu/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-slash-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-slash-menu/package.json b/solid-slash-menu/package.json new file mode 100644 index 0000000000..b2b2b7fe34 --- /dev/null +++ b/solid-slash-menu/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-slash-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-slash-menu/src/App.tsx b/solid-slash-menu/src/App.tsx new file mode 100644 index 0000000000..cf430661be --- /dev/null +++ b/solid-slash-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/slash-menu' + +export default function App() { + return +} diff --git a/solid-slash-menu/src/app.css b/solid-slash-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-slash-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-slash-menu/src/components/editor/examples/slash-menu/editor.tsx b/solid-slash-menu/src/components/editor/examples/slash-menu/editor.tsx new file mode 100644 index 0000000000..d7d2bede2d --- /dev/null +++ b/solid-slash-menu/src/components/editor/examples/slash-menu/editor.tsx @@ -0,0 +1,29 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { SlashMenu } from '../../ui/slash-menu' + +import { defineExtension } from './extension' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/solid-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/solid-slash-menu/src/components/editor/examples/slash-menu/extension.ts new file mode 100644 index 0000000000..0edda60136 --- /dev/null +++ b/solid-slash-menu/src/components/editor/examples/slash-menu/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-slash-menu/src/components/editor/examples/slash-menu/index.ts b/solid-slash-menu/src/components/editor/examples/slash-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-slash-menu/src/components/editor/examples/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-slash-menu/src/components/editor/ui/slash-menu/index.ts b/solid-slash-menu/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..b7f6969c32 --- /dev/null +++ b/solid-slash-menu/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu' diff --git a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx new file mode 100644 index 0000000000..aae5f3dc6b --- /dev/null +++ b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.tsx @@ -0,0 +1,10 @@ +import { AutocompleteEmpty } from 'prosekit/solid/autocomplete' +import type { JSX } from 'solid-js' + +export default function SlashMenuEmpty(): JSX.Element { + return ( + + No results + + ) +} diff --git a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx new file mode 100644 index 0000000000..9d8101d019 --- /dev/null +++ b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.tsx @@ -0,0 +1,22 @@ +import { AutocompleteItem } from 'prosekit/solid/autocomplete' +import { Show, type JSX } from 'solid-js' + +export default function SlashMenuItem(props: { + label: string + kbd?: string + onSelect: () => void +}): JSX.Element { + return ( + + {props.label} + + + {props.kbd} + + + + ) +} diff --git a/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx new file mode 100644 index 0000000000..c7090d7f36 --- /dev/null +++ b/solid-slash-menu/src/components/editor/ui/slash-menu/slash-menu.tsx @@ -0,0 +1,101 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind } from 'prosekit/core' +import { useEditor } from 'prosekit/solid' +import { + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/solid/autocomplete' +import type { JSX } from 'solid-js' + +import SlashMenuEmpty from './slash-menu-empty' +import SlashMenuItem from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?() + + return ( + + + +
+ editor().commands.setParagraph()} + /> + + editor().commands.setHeading({ level: 1 })} + /> + + editor().commands.setHeading({ level: 2 })} + /> + + editor().commands.setHeading({ level: 3 })} + /> + + editor().commands.wrapInList({ kind: 'bullet' })} + /> + + editor().commands.wrapInList({ kind: 'ordered' })} + /> + + editor().commands.wrapInList({ kind: 'task' })} + /> + + editor().commands.wrapInList({ kind: 'toggle' })} + /> + + editor().commands.setBlockquote()} + /> + + editor().commands.insertTable({ row: 3, col: 3 })} + /> + + editor().commands.insertHorizontalRule()} + /> + + editor().commands.setCodeBlock()} + /> + + +
+
+
+
+ ) +} diff --git a/solid-slash-menu/src/index.tsx b/solid-slash-menu/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-slash-menu/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-slash-menu/tsconfig.app.json b/solid-slash-menu/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-slash-menu/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-slash-menu/tsconfig.json b/solid-slash-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-slash-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-slash-menu/tsconfig.node.json b/solid-slash-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-slash-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-slash-menu/vite.config.ts b/solid-slash-menu/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-slash-menu/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-strike/.gitignore b/solid-strike/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-strike/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-strike/README.md b/solid-strike/README.md new file mode 100644 index 0000000000..4d17f223fe --- /dev/null +++ b/solid-strike/README.md @@ -0,0 +1,15 @@ +# solid-strike + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-strike) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-strike) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-strike solid-strike +cd solid-strike +npm install +npm run dev +``` diff --git a/solid-strike/index.html b/solid-strike/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-strike/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-strike/package.json b/solid-strike/package.json new file mode 100644 index 0000000000..07a4942dc6 --- /dev/null +++ b/solid-strike/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-strike", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-strike/src/App.tsx b/solid-strike/src/App.tsx new file mode 100644 index 0000000000..497a57c0d8 --- /dev/null +++ b/solid-strike/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/strike' + +export default function App() { + return +} diff --git a/solid-strike/src/app.css b/solid-strike/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-strike/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-strike/src/components/editor/examples/strike/editor.tsx b/solid-strike/src/components/editor/examples/strike/editor.tsx new file mode 100644 index 0000000000..cbf49c22df --- /dev/null +++ b/solid-strike/src/components/editor/examples/strike/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-strike' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-strike/src/components/editor/examples/strike/extension.ts b/solid-strike/src/components/editor/examples/strike/extension.ts new file mode 100644 index 0000000000..c013303ccc --- /dev/null +++ b/solid-strike/src/components/editor/examples/strike/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineStrike(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-strike/src/components/editor/examples/strike/index.ts b/solid-strike/src/components/editor/examples/strike/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-strike/src/components/editor/examples/strike/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-strike/src/components/editor/examples/strike/toolbar.tsx b/solid-strike/src/components/editor/examples/strike/toolbar.tsx new file mode 100644 index 0000000000..1b49d9cf93 --- /dev/null +++ b/solid-strike/src/components/editor/examples/strike/toolbar.tsx @@ -0,0 +1,33 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + strike: { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + }, + } +} + +export default function Toolbar(): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ +
+ ) +} diff --git a/solid-strike/src/components/editor/sample/sample-doc-strike.ts b/solid-strike/src/components/editor/sample/sample-doc-strike.ts new file mode 100644 index 0000000000..2e025e9b02 --- /dev/null +++ b/solid-strike/src/components/editor/sample/sample-doc-strike.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'This is strike', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/solid-strike/src/components/editor/ui/button/button.tsx b/solid-strike/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-strike/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-strike/src/components/editor/ui/button/index.ts b/solid-strike/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-strike/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-strike/src/index.tsx b/solid-strike/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-strike/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-strike/tsconfig.app.json b/solid-strike/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-strike/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-strike/tsconfig.json b/solid-strike/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-strike/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-strike/tsconfig.node.json b/solid-strike/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-strike/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-strike/vite.config.ts b/solid-strike/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-strike/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-sub-sup/.gitignore b/solid-sub-sup/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-sub-sup/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-sub-sup/README.md b/solid-sub-sup/README.md new file mode 100644 index 0000000000..df2195fdc0 --- /dev/null +++ b/solid-sub-sup/README.md @@ -0,0 +1,15 @@ +# solid-sub-sup + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-sub-sup) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-sub-sup) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-sub-sup solid-sub-sup +cd solid-sub-sup +npm install +npm run dev +``` diff --git a/solid-sub-sup/index.html b/solid-sub-sup/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-sub-sup/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-sub-sup/package.json b/solid-sub-sup/package.json new file mode 100644 index 0000000000..31a570e274 --- /dev/null +++ b/solid-sub-sup/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-sub-sup", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-sub-sup/src/App.tsx b/solid-sub-sup/src/App.tsx new file mode 100644 index 0000000000..48e43d6423 --- /dev/null +++ b/solid-sub-sup/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/sub-sup' + +export default function App() { + return +} diff --git a/solid-sub-sup/src/app.css b/solid-sub-sup/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-sub-sup/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-sub-sup/src/components/editor/examples/sub-sup/editor.tsx b/solid-sub-sup/src/components/editor/examples/sub-sup/editor.tsx new file mode 100644 index 0000000000..2ed42e8a55 --- /dev/null +++ b/solid-sub-sup/src/components/editor/examples/sub-sup/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-sub-sup' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/solid-sub-sup/src/components/editor/examples/sub-sup/extension.ts new file mode 100644 index 0000000000..bd67245f86 --- /dev/null +++ b/solid-sub-sup/src/components/editor/examples/sub-sup/extension.ts @@ -0,0 +1,32 @@ +import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineMarkInputRule } from 'prosekit/extensions/input-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineSubscript } from 'prosekit/extensions/subscript' +import { defineSuperscript } from 'prosekit/extensions/superscript' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineSubscript(), + defineSuperscript(), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ + : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, + type: 'subscript', + }), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ + : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, + type: 'superscript', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-sub-sup/src/components/editor/examples/sub-sup/index.ts b/solid-sub-sup/src/components/editor/examples/sub-sup/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-sub-sup/src/components/editor/examples/sub-sup/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx b/solid-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx new file mode 100644 index 0000000000..c8af70b72c --- /dev/null +++ b/solid-sub-sup/src/components/editor/examples/sub-sup/toolbar.tsx @@ -0,0 +1,45 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function getToolbarItems(editor: Editor) { + return { + subscript: { + isActive: editor.marks.subscript.isActive(), + canExec: editor.commands.toggleSubscript.canExec(), + command: () => editor.commands.toggleSubscript(), + }, + superscript: { + isActive: editor.marks.superscript.isActive(), + canExec: editor.commands.toggleSuperscript.canExec(), + command: () => editor.commands.toggleSuperscript(), + }, + } +} + +export default function Toolbar(): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + +
+ ) +} diff --git a/solid-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/solid-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts new file mode 100644 index 0000000000..011be750dc --- /dev/null +++ b/solid-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts @@ -0,0 +1,42 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'H', + }, + { + type: 'text', + marks: [ + { + type: 'subscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: 'O is water. x', + }, + { + type: 'text', + marks: [ + { + type: 'superscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: ' is a square.', + }, + ], + }, + ], +} diff --git a/solid-sub-sup/src/components/editor/ui/button/button.tsx b/solid-sub-sup/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-sub-sup/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-sub-sup/src/components/editor/ui/button/index.ts b/solid-sub-sup/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-sub-sup/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-sub-sup/src/index.tsx b/solid-sub-sup/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-sub-sup/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-sub-sup/tsconfig.app.json b/solid-sub-sup/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-sub-sup/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-sub-sup/tsconfig.json b/solid-sub-sup/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-sub-sup/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-sub-sup/tsconfig.node.json b/solid-sub-sup/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-sub-sup/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-sub-sup/vite.config.ts b/solid-sub-sup/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-sub-sup/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-table/.gitignore b/solid-table/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-table/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-table/README.md b/solid-table/README.md new file mode 100644 index 0000000000..ff407bb97d --- /dev/null +++ b/solid-table/README.md @@ -0,0 +1,15 @@ +# solid-table + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-table) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-table) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-table solid-table +cd solid-table +npm install +npm run dev +``` diff --git a/solid-table/index.html b/solid-table/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-table/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-table/package.json b/solid-table/package.json new file mode 100644 index 0000000000..3a08f98662 --- /dev/null +++ b/solid-table/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-table", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-table/src/App.tsx b/solid-table/src/App.tsx new file mode 100644 index 0000000000..9d9d957adb --- /dev/null +++ b/solid-table/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/table' + +export default function App() { + return +} diff --git a/solid-table/src/app.css b/solid-table/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-table/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-table/src/components/editor/examples/table/editor.tsx b/solid-table/src/components/editor/examples/table/editor.tsx new file mode 100644 index 0000000000..b8b4f1cef1 --- /dev/null +++ b/solid-table/src/components/editor/examples/table/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-table' +import { TableHandle } from '../../ui/table-handle' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/solid-table/src/components/editor/examples/table/extension.ts b/solid-table/src/components/editor/examples/table/extension.ts new file mode 100644 index 0000000000..ee7b142041 --- /dev/null +++ b/solid-table/src/components/editor/examples/table/extension.ts @@ -0,0 +1,20 @@ +import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineTable(), + defineHistory(), + defineGapCursor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-table/src/components/editor/examples/table/index.ts b/solid-table/src/components/editor/examples/table/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-table/src/components/editor/examples/table/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-table/src/components/editor/sample/sample-doc-table.ts b/solid-table/src/components/editor/sample/sample-doc-table.ts new file mode 100644 index 0000000000..c737121672 --- /dev/null +++ b/solid-table/src/components/editor/sample/sample-doc-table.ts @@ -0,0 +1,174 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D1', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D2', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], +} diff --git a/solid-table/src/components/editor/ui/table-handle/index.ts b/solid-table/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..f8b273396e --- /dev/null +++ b/solid-table/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle' diff --git a/solid-table/src/components/editor/ui/table-handle/table-handle.tsx b/solid-table/src/components/editor/ui/table-handle/table-handle.tsx new file mode 100644 index 0000000000..463f4d3657 --- /dev/null +++ b/solid-table/src/components/editor/ui/table-handle/table-handle.tsx @@ -0,0 +1,187 @@ +import type { Editor } from 'prosekit/core' +import type { TableExtension } from 'prosekit/extensions/table' +import { useEditorDerivedValue } from 'prosekit/solid' +import { MenuItem, MenuPopup, MenuPositioner } from 'prosekit/solid/menu' +import { + TableHandleColumnMenuRoot, + TableHandleColumnMenuTrigger, + TableHandleColumnPopup, + TableHandleColumnPositioner, + TableHandleDragPreview, + TableHandleDropIndicator, + TableHandleRoot, + TableHandleRowMenuRoot, + TableHandleRowMenuTrigger, + TableHandleRowPopup, + TableHandleRowPositioner, +} from 'prosekit/solid/table-handle' +import { Show, type JSX } from 'solid-js' + +function getTableHandleState(editor: Editor) { + return { + addTableColumnBefore: { + canExec: editor.commands.addTableColumnBefore.canExec(), + command: () => editor.commands.addTableColumnBefore(), + }, + addTableColumnAfter: { + canExec: editor.commands.addTableColumnAfter.canExec(), + command: () => editor.commands.addTableColumnAfter(), + }, + deleteCellSelection: { + canExec: editor.commands.deleteCellSelection.canExec(), + command: () => editor.commands.deleteCellSelection(), + }, + deleteTableColumn: { + canExec: editor.commands.deleteTableColumn.canExec(), + command: () => editor.commands.deleteTableColumn(), + }, + addTableRowAbove: { + canExec: editor.commands.addTableRowAbove.canExec(), + command: () => editor.commands.addTableRowAbove(), + }, + addTableRowBelow: { + canExec: editor.commands.addTableRowBelow.canExec(), + command: () => editor.commands.addTableRowBelow(), + }, + deleteTableRow: { + canExec: editor.commands.deleteTableRow.canExec(), + command: () => editor.commands.deleteTableRow(), + }, + deleteTable: { + canExec: editor.commands.deleteTable.canExec(), + command: () => editor.commands.deleteTable(), + }, + } +} + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function TableHandle(props: Props): JSX.Element { + const state = useEditorDerivedValue(getTableHandleState) + + return ( + + + + + + + +
+
+ + + + state().addTableColumnBefore.command()} + > + Insert Left + + + + state().addTableColumnAfter.command()} + > + Insert Right + + + + state().deleteCellSelection.command()} + > + Clear Contents + + Del + + + + + state().deleteTableColumn.command()} + > + Delete Column + + + + state().deleteTable.command()} + > + Delete Table + + + + +
+
+
+ + + + +
+
+ + + + state().addTableRowAbove.command()} + > + Insert Above + + + + state().addTableRowBelow.command()} + > + Insert Below + + + + state().deleteCellSelection.command()} + > + Clear Contents + + Del + + + + + state().deleteTableRow.command()} + > + Delete Row + + + + state().deleteTable.command()} + > + Delete Table + + + + +
+
+
+
+ ) +} diff --git a/solid-table/src/index.tsx b/solid-table/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-table/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-table/tsconfig.app.json b/solid-table/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-table/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-table/tsconfig.json b/solid-table/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-table/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-table/tsconfig.node.json b/solid-table/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-table/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-table/vite.config.ts b/solid-table/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-table/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-text-align/.gitignore b/solid-text-align/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-text-align/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-text-align/README.md b/solid-text-align/README.md new file mode 100644 index 0000000000..7a75a58ede --- /dev/null +++ b/solid-text-align/README.md @@ -0,0 +1,15 @@ +# solid-text-align + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-text-align) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-text-align) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-text-align solid-text-align +cd solid-text-align +npm install +npm run dev +``` diff --git a/solid-text-align/index.html b/solid-text-align/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-text-align/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-text-align/package.json b/solid-text-align/package.json new file mode 100644 index 0000000000..1a71d4ce59 --- /dev/null +++ b/solid-text-align/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-text-align", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-text-align/src/App.tsx b/solid-text-align/src/App.tsx new file mode 100644 index 0000000000..0c049df602 --- /dev/null +++ b/solid-text-align/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/text-align' + +export default function App() { + return +} diff --git a/solid-text-align/src/app.css b/solid-text-align/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-text-align/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-text-align/src/components/editor/examples/text-align/editor.tsx b/solid-text-align/src/components/editor/examples/text-align/editor.tsx new file mode 100644 index 0000000000..2c8c3bbfa4 --- /dev/null +++ b/solid-text-align/src/components/editor/examples/text-align/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-text-align' + +import { defineExtension } from './extension' +import Toolbar from './toolbar' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-text-align/src/components/editor/examples/text-align/extension.ts b/solid-text-align/src/components/editor/examples/text-align/extension.ts new file mode 100644 index 0000000000..f1ae44dc7c --- /dev/null +++ b/solid-text-align/src/components/editor/examples/text-align/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineTextAlign } from 'prosekit/extensions/text-align' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextAlign({ types: ['paragraph', 'heading'] }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-text-align/src/components/editor/examples/text-align/index.ts b/solid-text-align/src/components/editor/examples/text-align/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-text-align/src/components/editor/examples/text-align/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-text-align/src/components/editor/examples/text-align/toolbar.tsx b/solid-text-align/src/components/editor/examples/text-align/toolbar.tsx new file mode 100644 index 0000000000..8c11774886 --- /dev/null +++ b/solid-text-align/src/components/editor/examples/text-align/toolbar.tsx @@ -0,0 +1,79 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +function isTextAlignActive(editor: Editor, value: string) { + return Object.values(editor.nodes).some((node) => { + // @ts-expect-error textAlign may not be available on every node + return node.isActive({ textAlign: value }) + }) +} + +function getToolbarItems(editor: Editor) { + return { + left: { + isActive: isTextAlignActive(editor, 'left'), + canExec: editor.commands.setTextAlign.canExec('left'), + command: () => editor.commands.setTextAlign('left'), + }, + center: { + isActive: isTextAlignActive(editor, 'center'), + canExec: editor.commands.setTextAlign.canExec('center'), + command: () => editor.commands.setTextAlign('center'), + }, + right: { + isActive: isTextAlignActive(editor, 'right'), + canExec: editor.commands.setTextAlign.canExec('right'), + command: () => editor.commands.setTextAlign('right'), + }, + justify: { + isActive: isTextAlignActive(editor, 'justify'), + canExec: editor.commands.setTextAlign.canExec('justify'), + command: () => editor.commands.setTextAlign('justify'), + }, + } +} + +export default function Toolbar(): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + + + + + + +
+ ) +} diff --git a/solid-text-align/src/components/editor/sample/sample-doc-text-align.ts b/solid-text-align/src/components/editor/sample/sample-doc-text-align.ts new file mode 100644 index 0000000000..0724cea4f7 --- /dev/null +++ b/solid-text-align/src/components/editor/sample/sample-doc-text-align.ts @@ -0,0 +1,56 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Heading', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'left', + }, + content: [ + { + type: 'text', + text: 'First paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Second paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'right', + }, + content: [ + { + type: 'text', + text: 'Third paragraph', + }, + ], + }, + ], +} diff --git a/solid-text-align/src/components/editor/ui/button/button.tsx b/solid-text-align/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-text-align/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-text-align/src/components/editor/ui/button/index.ts b/solid-text-align/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-text-align/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-text-align/src/index.tsx b/solid-text-align/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-text-align/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-text-align/tsconfig.app.json b/solid-text-align/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-text-align/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-text-align/tsconfig.json b/solid-text-align/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-text-align/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-text-align/tsconfig.node.json b/solid-text-align/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-text-align/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-text-align/vite.config.ts b/solid-text-align/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-text-align/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-text-color/.gitignore b/solid-text-color/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-text-color/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-text-color/README.md b/solid-text-color/README.md new file mode 100644 index 0000000000..894ae982fe --- /dev/null +++ b/solid-text-color/README.md @@ -0,0 +1,15 @@ +# solid-text-color + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-text-color) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-text-color) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-text-color solid-text-color +cd solid-text-color +npm install +npm run dev +``` diff --git a/solid-text-color/index.html b/solid-text-color/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-text-color/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-text-color/package.json b/solid-text-color/package.json new file mode 100644 index 0000000000..caeb7d290b --- /dev/null +++ b/solid-text-color/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-text-color", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-text-color/src/App.tsx b/solid-text-color/src/App.tsx new file mode 100644 index 0000000000..1225de322a --- /dev/null +++ b/solid-text-color/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/text-color' + +export default function App() { + return +} diff --git a/solid-text-color/src/app.css b/solid-text-color/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-text-color/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-text-color/src/components/editor/examples/text-color/editor.tsx b/solid-text-color/src/components/editor/examples/text-color/editor.tsx new file mode 100644 index 0000000000..ee7b9f6b11 --- /dev/null +++ b/solid-text-color/src/components/editor/examples/text-color/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-text-color' + +import { defineExtension } from './extension' +import InlineMenu from './inline-menu' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/solid-text-color/src/components/editor/examples/text-color/extension.ts b/solid-text-color/src/components/editor/examples/text-color/extension.ts new file mode 100644 index 0000000000..d35d9d5c22 --- /dev/null +++ b/solid-text-color/src/components/editor/examples/text-color/extension.ts @@ -0,0 +1,14 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineBackgroundColor } from 'prosekit/extensions/background-color' +import { defineTextColor } from 'prosekit/extensions/text-color' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextColor(), + defineBackgroundColor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-text-color/src/components/editor/examples/text-color/index.ts b/solid-text-color/src/components/editor/examples/text-color/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-text-color/src/components/editor/examples/text-color/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-text-color/src/components/editor/examples/text-color/inline-menu.tsx b/solid-text-color/src/components/editor/examples/text-color/inline-menu.tsx new file mode 100644 index 0000000000..c85523bba7 --- /dev/null +++ b/solid-text-color/src/components/editor/examples/text-color/inline-menu.tsx @@ -0,0 +1,144 @@ +import type { Editor, Keymap } from 'prosekit/core' +import { useEditorDerivedValue, useKeymap } from 'prosekit/solid' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/solid/inline-popover' +import { createSignal, For, type JSX } from 'solid-js' + +import { Button } from '../../ui/button' + +import type { EditorExtension } from './extension' + +const textColors = [ + { label: 'Gray', value: '#9ca3af' }, + { label: 'Brown', value: '#92400e' }, + { label: 'Orange', value: '#ea580c' }, + { label: 'Yellow', value: '#ca8a04' }, + { label: 'Green', value: '#16a34a' }, + { label: 'Blue', value: '#2563eb' }, + { label: 'Purple', value: '#9333ea' }, + { label: 'Magenta', value: '#c026d3' }, + { label: 'Red', value: '#dc2626' }, +] + +const backgroundColors = [ + { label: 'Gray', value: '#f3f4f6' }, + { label: 'Brown', value: '#fef3c7' }, + { label: 'Orange', value: '#ffedd5' }, + { label: 'Yellow', value: '#fef9c3' }, + { label: 'Green', value: '#d1fae5' }, + { label: 'Blue', value: '#dbeafe' }, + { label: 'Purple', value: '#e9d5ff' }, + { label: 'Pink', value: '#fce7f3' }, + { label: 'Red', value: '#fecaca' }, +] + +function getTextColorState(editor: Editor) { + return [ + { + label: 'Default', + value: 'currentColor', + isActive: !editor.marks.textColor.isActive(), + onClick: () => editor.commands.removeTextColor(), + }, + ].concat( + textColors.map((color) => ({ + label: color.label, + value: color.value, + isActive: editor.marks.textColor.isActive({ color: color.value }), + onClick: () => editor.commands.addTextColor({ color: color.value }), + })), + ) +} + +function getBackgroundColorState(editor: Editor) { + return [ + { + label: 'Default', + value: 'canvas', + isActive: !editor.marks.backgroundColor.isActive(), + onClick: () => editor.commands.removeBackgroundColor(), + }, + ].concat( + backgroundColors.map((color) => ({ + label: color.label, + value: color.value, + isActive: editor.marks.backgroundColor.isActive({ color: color.value }), + onClick: () => editor.commands.addBackgroundColor({ color: color.value }), + })), + ) +} + +export default function InlineMenu(): JSX.Element { + const textColorState = useEditorDerivedValue(getTextColorState) + const backgroundColorState = useEditorDerivedValue(getBackgroundColorState) + const [open, setOpen] = createSignal(false) + + const keymap: () => Keymap = () => ({ + Escape: () => { + if (open()) { + setOpen(false) + return true + } + return false + }, + }) + + useKeymap(keymap) + + return ( + setOpen(event.detail)} + > + + +
+
+
Text color
+
+ + {(color) => ( + + )} + +
+
+
+
Background color
+
+ + {(color) => ( + + )} + +
+
+
+
+
+
+ ) +} diff --git a/solid-text-color/src/components/editor/sample/sample-doc-text-color.ts b/solid-text-color/src/components/editor/sample/sample-doc-text-color.ts new file mode 100644 index 0000000000..a4efe4308d --- /dev/null +++ b/solid-text-color/src/components/editor/sample/sample-doc-text-color.ts @@ -0,0 +1,120 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#ef4444', + }, + }, + ], + text: 'Select', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#f97316', + }, + }, + ], + text: 'some', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#eab308', + }, + }, + ], + text: 'text', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#22c55e', + }, + }, + ], + text: 'to', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#3b82f6', + }, + }, + ], + text: 'change', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#6366f1', + }, + }, + ], + text: 'the', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#a855f7', + }, + }, + ], + text: 'color', + }, + ], + }, + ], +} diff --git a/solid-text-color/src/components/editor/ui/button/button.tsx b/solid-text-color/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-text-color/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-text-color/src/components/editor/ui/button/index.ts b/solid-text-color/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-text-color/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-text-color/src/index.tsx b/solid-text-color/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-text-color/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-text-color/tsconfig.app.json b/solid-text-color/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-text-color/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-text-color/tsconfig.json b/solid-text-color/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-text-color/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-text-color/tsconfig.node.json b/solid-text-color/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-text-color/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-text-color/vite.config.ts b/solid-text-color/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-text-color/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-toolbar/.gitignore b/solid-toolbar/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-toolbar/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-toolbar/README.md b/solid-toolbar/README.md new file mode 100644 index 0000000000..2c16e8d66e --- /dev/null +++ b/solid-toolbar/README.md @@ -0,0 +1,15 @@ +# solid-toolbar + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-toolbar) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-toolbar) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-toolbar solid-toolbar +cd solid-toolbar +npm install +npm run dev +``` diff --git a/solid-toolbar/index.html b/solid-toolbar/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-toolbar/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-toolbar/package.json b/solid-toolbar/package.json new file mode 100644 index 0000000000..e1bf875de4 --- /dev/null +++ b/solid-toolbar/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-toolbar", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-toolbar/src/App.tsx b/solid-toolbar/src/App.tsx new file mode 100644 index 0000000000..72699e4f11 --- /dev/null +++ b/solid-toolbar/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/toolbar' + +export default function App() { + return +} diff --git a/solid-toolbar/src/app.css b/solid-toolbar/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-toolbar/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-toolbar/src/components/editor/examples/toolbar/editor.tsx b/solid-toolbar/src/components/editor/examples/toolbar/editor.tsx new file mode 100644 index 0000000000..8523725ffd --- /dev/null +++ b/solid-toolbar/src/components/editor/examples/toolbar/editor.tsx @@ -0,0 +1,30 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleUploader } from '../../sample/sample-uploader' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-toolbar/src/components/editor/examples/toolbar/extension.ts b/solid-toolbar/src/components/editor/examples/toolbar/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/solid-toolbar/src/components/editor/examples/toolbar/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/solid-toolbar/src/components/editor/examples/toolbar/index.ts b/solid-toolbar/src/components/editor/examples/toolbar/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-toolbar/src/components/editor/examples/toolbar/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-toolbar/src/components/editor/sample/sample-uploader.ts b/solid-toolbar/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/solid-toolbar/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/solid-toolbar/src/components/editor/ui/button/button.tsx b/solid-toolbar/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-toolbar/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-toolbar/src/components/editor/ui/button/index.ts b/solid-toolbar/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-toolbar/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/solid-toolbar/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-toolbar/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-toolbar/src/components/editor/ui/toolbar/index.ts b/solid-toolbar/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-toolbar/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-toolbar/src/components/editor/ui/toolbar/toolbar.tsx b/solid-toolbar/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-toolbar/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-toolbar/src/index.tsx b/solid-toolbar/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-toolbar/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-toolbar/tsconfig.app.json b/solid-toolbar/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-toolbar/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-toolbar/tsconfig.json b/solid-toolbar/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-toolbar/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-toolbar/tsconfig.node.json b/solid-toolbar/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-toolbar/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-toolbar/vite.config.ts b/solid-toolbar/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-toolbar/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-typography/.gitignore b/solid-typography/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-typography/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-typography/README.md b/solid-typography/README.md new file mode 100644 index 0000000000..00298fb7ce --- /dev/null +++ b/solid-typography/README.md @@ -0,0 +1,15 @@ +# solid-typography + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-typography) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-typography) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-typography solid-typography +cd solid-typography +npm install +npm run dev +``` diff --git a/solid-typography/index.html b/solid-typography/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-typography/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-typography/package.json b/solid-typography/package.json new file mode 100644 index 0000000000..d4517ea466 --- /dev/null +++ b/solid-typography/package.json @@ -0,0 +1,26 @@ +{ + "name": "example-solid-typography", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-typography/src/App.tsx b/solid-typography/src/App.tsx new file mode 100644 index 0000000000..e1a59aa483 --- /dev/null +++ b/solid-typography/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/typography' + +export default function App() { + return +} diff --git a/solid-typography/src/app.css b/solid-typography/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-typography/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-typography/src/components/editor/examples/typography/editor.tsx b/solid-typography/src/components/editor/examples/typography/editor.tsx new file mode 100644 index 0000000000..219dc02cc6 --- /dev/null +++ b/solid-typography/src/components/editor/examples/typography/editor.tsx @@ -0,0 +1,37 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-typography' +import { BlockHandle } from '../../ui/block-handle' +import { DropIndicator } from '../../ui/drop-indicator' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/solid-typography/src/components/editor/examples/typography/extension.ts b/solid-typography/src/components/editor/examples/typography/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/solid-typography/src/components/editor/examples/typography/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-typography/src/components/editor/examples/typography/index.ts b/solid-typography/src/components/editor/examples/typography/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-typography/src/components/editor/examples/typography/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-typography/src/components/editor/sample/katex.ts b/solid-typography/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/solid-typography/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/solid-typography/src/components/editor/sample/sample-doc-typography.ts b/solid-typography/src/components/editor/sample/sample-doc-typography.ts new file mode 100644 index 0000000000..db18b8155c --- /dev/null +++ b/solid-typography/src/components/editor/sample/sample-doc-typography.ts @@ -0,0 +1,693 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'ProseKit Typography', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This example shows the typography styles provided by ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'prosekit/basic/typography.css', + }, + { + type: 'text', + text: '.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Inline marks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Text can be formatted in different ways: ', + }, + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'bold text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'italic text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'underlined text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'strikethrough text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'inline code', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://example.com', + target: null, + rel: null, + }, + }, + ], + text: 'links', + }, + { + type: 'text', + text: ',', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'and hard breaks (Shift+Enter).', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Headings', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Heading 1', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Heading 2', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Heading 3', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 4, + }, + content: [ + { + type: 'text', + text: 'Heading 4', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 5, + }, + content: [ + { + type: 'text', + text: 'Heading 5', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 6, + }, + content: [ + { + type: 'text', + text: 'Heading 6', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Lists', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here are different types of lists:', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 1', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 2', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item A', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item B', + }, + ], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'First ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Second ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: true, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Completed task', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Pending task', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Blockquotes', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: '', + }, + content: [ + { + type: 'text', + text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Horizontal Rule', + }, + ], + }, + { + type: 'horizontalRule', + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blurred/640x360/42', + }, + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Tables', + }, + ], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 1', + }, + ], + }, + ], + }, + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 3', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 4', + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Math', + }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Inline math like Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text.' }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Block-level equations are displayed on their own line:', + }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + ], +} diff --git a/solid-typography/src/components/editor/ui/block-handle/block-handle.tsx b/solid-typography/src/components/editor/ui/block-handle/block-handle.tsx new file mode 100644 index 0000000000..95e1693ef6 --- /dev/null +++ b/solid-typography/src/components/editor/ui/block-handle/block-handle.tsx @@ -0,0 +1,32 @@ +import { + BlockHandleAdd, + BlockHandleDraggable, + BlockHandlePopup, + BlockHandlePositioner, + BlockHandleRoot, +} from 'prosekit/solid/block-handle' +import type { JSX } from 'solid-js' + +interface Props { + dir?: 'ltr' | 'rtl' +} + +export default function BlockHandle(props: Props): JSX.Element { + return ( + + + + +
+ + +
+ + + + + ) +} diff --git a/solid-typography/src/components/editor/ui/block-handle/index.ts b/solid-typography/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..43efe9ce3f --- /dev/null +++ b/solid-typography/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle' diff --git a/solid-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx b/solid-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx new file mode 100644 index 0000000000..c5a24c7faa --- /dev/null +++ b/solid-typography/src/components/editor/ui/drop-indicator/drop-indicator.tsx @@ -0,0 +1,6 @@ +import { DropIndicator as BaseDropIndicator } from 'prosekit/solid/drop-indicator' +import type { JSX } from 'solid-js' + +export default function DropIndicator(): JSX.Element { + return +} diff --git a/solid-typography/src/components/editor/ui/drop-indicator/index.ts b/solid-typography/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..f8fb7139c4 --- /dev/null +++ b/solid-typography/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator' diff --git a/solid-typography/src/index.tsx b/solid-typography/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-typography/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-typography/tsconfig.app.json b/solid-typography/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-typography/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-typography/tsconfig.json b/solid-typography/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-typography/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-typography/tsconfig.node.json b/solid-typography/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-typography/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-typography/vite.config.ts b/solid-typography/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-typography/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-underline/.gitignore b/solid-underline/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-underline/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-underline/README.md b/solid-underline/README.md new file mode 100644 index 0000000000..19cbc2a06d --- /dev/null +++ b/solid-underline/README.md @@ -0,0 +1,15 @@ +# solid-underline + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-underline) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-underline) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-underline solid-underline +cd solid-underline +npm install +npm run dev +``` diff --git a/solid-underline/index.html b/solid-underline/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-underline/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-underline/package.json b/solid-underline/package.json new file mode 100644 index 0000000000..01c4fae370 --- /dev/null +++ b/solid-underline/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-underline", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-underline/src/App.tsx b/solid-underline/src/App.tsx new file mode 100644 index 0000000000..6a03ee7870 --- /dev/null +++ b/solid-underline/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/underline' + +export default function App() { + return +} diff --git a/solid-underline/src/app.css b/solid-underline/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-underline/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-underline/src/components/editor/examples/underline/editor.tsx b/solid-underline/src/components/editor/examples/underline/editor.tsx new file mode 100644 index 0000000000..b4d246969c --- /dev/null +++ b/solid-underline/src/components/editor/examples/underline/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-underline' +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-underline/src/components/editor/examples/underline/extension.ts b/solid-underline/src/components/editor/examples/underline/extension.ts new file mode 100644 index 0000000000..16a9b58284 --- /dev/null +++ b/solid-underline/src/components/editor/examples/underline/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineUnderline(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-underline/src/components/editor/examples/underline/index.ts b/solid-underline/src/components/editor/examples/underline/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-underline/src/components/editor/examples/underline/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-underline/src/components/editor/sample/sample-doc-underline.ts b/solid-underline/src/components/editor/sample/sample-doc-underline.ts new file mode 100644 index 0000000000..6af561064b --- /dev/null +++ b/solid-underline/src/components/editor/sample/sample-doc-underline.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'This is underline', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/solid-underline/src/components/editor/ui/button/button.tsx b/solid-underline/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-underline/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-underline/src/components/editor/ui/button/index.ts b/solid-underline/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-underline/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-underline/src/components/editor/ui/image-upload-popover/index.ts b/solid-underline/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-underline/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-underline/src/components/editor/ui/toolbar/index.ts b/solid-underline/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-underline/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-underline/src/components/editor/ui/toolbar/toolbar.tsx b/solid-underline/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-underline/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-underline/src/index.tsx b/solid-underline/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-underline/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-underline/tsconfig.app.json b/solid-underline/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-underline/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-underline/tsconfig.json b/solid-underline/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-underline/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-underline/tsconfig.node.json b/solid-underline/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-underline/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-underline/vite.config.ts b/solid-underline/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-underline/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-unmount/.gitignore b/solid-unmount/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-unmount/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-unmount/README.md b/solid-unmount/README.md new file mode 100644 index 0000000000..5d93fa426e --- /dev/null +++ b/solid-unmount/README.md @@ -0,0 +1,15 @@ +# solid-unmount + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-unmount) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-unmount) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-unmount solid-unmount +cd solid-unmount +npm install +npm run dev +``` diff --git a/solid-unmount/index.html b/solid-unmount/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-unmount/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-unmount/package.json b/solid-unmount/package.json new file mode 100644 index 0000000000..d555a4a6d3 --- /dev/null +++ b/solid-unmount/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-unmount", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-unmount/src/App.tsx b/solid-unmount/src/App.tsx new file mode 100644 index 0000000000..da35bea56f --- /dev/null +++ b/solid-unmount/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/unmount' + +export default function App() { + return +} diff --git a/solid-unmount/src/app.css b/solid-unmount/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-unmount/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-unmount/src/components/editor/examples/unmount/editor-component.tsx b/solid-unmount/src/components/editor/examples/unmount/editor-component.tsx new file mode 100644 index 0000000000..9eb7937ed2 --- /dev/null +++ b/solid-unmount/src/components/editor/examples/unmount/editor-component.tsx @@ -0,0 +1,33 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { InlineMenu } from '../../ui/inline-menu' + +import ExtensionComponent from './extension-component.tsx' + +export default function EditorComponent(props: { + placeholder: string +}): JSX.Element { + const extension = defineBasicExtension() + const editor = createEditor({ extension }) + + return ( + +
+
+
+ +
+
+ +
+ ) +} diff --git a/solid-unmount/src/components/editor/examples/unmount/editor.tsx b/solid-unmount/src/components/editor/examples/unmount/editor.tsx new file mode 100644 index 0000000000..daca583170 --- /dev/null +++ b/solid-unmount/src/components/editor/examples/unmount/editor.tsx @@ -0,0 +1,42 @@ +import { createSignal, For, type JSX } from 'solid-js' + +import EditorComponent from './editor-component' + +export default function Editor(): JSX.Element { + let nextKey = 1 + const [editorKeys, setEditorKeys] = createSignal([]) + + const addEditor = () => { + const key = nextKey + nextKey += 1 + setEditorKeys((keys) => [...keys, key]) + } + + const removeEditor = (key: number) => { + setEditorKeys((keys) => keys.filter((k) => k !== key)) + } + + return ( +
+
+ + + {(key) => ( + + )} + +
+ + {(key) => ( +
+ +
+ )} +
+
+ ) +} diff --git a/solid-unmount/src/components/editor/examples/unmount/extension-component.tsx b/solid-unmount/src/components/editor/examples/unmount/extension-component.tsx new file mode 100644 index 0000000000..7ae8a342a4 --- /dev/null +++ b/solid-unmount/src/components/editor/examples/unmount/extension-component.tsx @@ -0,0 +1,15 @@ +import { definePlaceholder } from 'prosekit/extensions/placeholder' +import { useExtension } from 'prosekit/solid' +import { createMemo, type JSX } from 'solid-js' + +export default function ExtensionComponent(props: { + placeholder: string +}): JSX.Element { + const extension = createMemo(() => { + return definePlaceholder({ placeholder: props.placeholder }) + }) + + useExtension(extension) + + return null +} diff --git a/solid-unmount/src/components/editor/examples/unmount/index.ts b/solid-unmount/src/components/editor/examples/unmount/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-unmount/src/components/editor/examples/unmount/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-unmount/src/components/editor/ui/button/button.tsx b/solid-unmount/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-unmount/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-unmount/src/components/editor/ui/button/index.ts b/solid-unmount/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-unmount/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-unmount/src/components/editor/ui/inline-menu/index.ts b/solid-unmount/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8ead2b5072 --- /dev/null +++ b/solid-unmount/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu' diff --git a/solid-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx b/solid-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx new file mode 100644 index 0000000000..d61df6d794 --- /dev/null +++ b/solid-unmount/src/components/editor/ui/inline-menu/inline-menu.tsx @@ -0,0 +1,233 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { LinkAttrs } from 'prosekit/extensions/link' +import type { EditorState } from 'prosekit/pm/state' +import { useEditor, useEditorDerivedValue } from 'prosekit/solid' +import { + InlinePopoverPopup, + InlinePopoverPositioner, + InlinePopoverRoot, +} from 'prosekit/solid/inline-popover' +import { createSignal, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +function getInlineMenuItems(editor: Editor) { + return { + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + link: editor.commands.addLink + ? { + isActive: editor.marks.link.isActive(), + canExec: editor.commands.addLink.canExec({ href: '' }), + command: () => editor.commands.expandLink(), + currentLink: getCurrentLink(editor.state) || '', + } + : undefined, + } +} + +function getCurrentLink(state: EditorState): string | undefined { + const { $from } = state.selection + const marks = $from.marksAcross($from) + if (!marks) { + return + } + for (const mark of marks) { + if (mark.type.name === 'link') { + return (mark.attrs as LinkAttrs).href + } + } +} + +export default function InlineMenu(): JSX.Element { + const editor = useEditor() + const items = useEditorDerivedValue(getInlineMenuItems) + + const [linkMenuOpen, setLinkMenuOpen] = createSignal(false) + const toggleLinkMenuOpen = () => setLinkMenuOpen((open) => !open) + + const handleLinkUpdate = (href?: string) => { + if (href) { + editor().commands.addLink({ href }) + } else { + editor().commands.removeLink() + } + + setLinkMenuOpen(false) + editor().focus() + } + + return ( + <> + { + if (!event.detail) { + setLinkMenuOpen(false) + } + }} + > + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + + + + {(item) => ( + setLinkMenuOpen(event.detail)} + > + + + +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+
+ + + +
+
+
+ )} +
+ + ) +} diff --git a/solid-unmount/src/index.tsx b/solid-unmount/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-unmount/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-unmount/tsconfig.app.json b/solid-unmount/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-unmount/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-unmount/tsconfig.json b/solid-unmount/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-unmount/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-unmount/tsconfig.node.json b/solid-unmount/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-unmount/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-unmount/vite.config.ts b/solid-unmount/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-unmount/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-user-menu-dynamic/.gitignore b/solid-user-menu-dynamic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-user-menu-dynamic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-user-menu-dynamic/README.md b/solid-user-menu-dynamic/README.md new file mode 100644 index 0000000000..750b82c1d7 --- /dev/null +++ b/solid-user-menu-dynamic/README.md @@ -0,0 +1,15 @@ +# solid-user-menu-dynamic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-user-menu-dynamic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-user-menu-dynamic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-user-menu-dynamic solid-user-menu-dynamic +cd solid-user-menu-dynamic +npm install +npm run dev +``` diff --git a/solid-user-menu-dynamic/index.html b/solid-user-menu-dynamic/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-user-menu-dynamic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-user-menu-dynamic/package.json b/solid-user-menu-dynamic/package.json new file mode 100644 index 0000000000..6515ef3026 --- /dev/null +++ b/solid-user-menu-dynamic/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-user-menu-dynamic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-user-menu-dynamic/src/App.tsx b/solid-user-menu-dynamic/src/App.tsx new file mode 100644 index 0000000000..e3ec0e7b10 --- /dev/null +++ b/solid-user-menu-dynamic/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/user-menu-dynamic' + +export default function App() { + return +} diff --git a/solid-user-menu-dynamic/src/app.css b/solid-user-menu-dynamic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-user-menu-dynamic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx new file mode 100644 index 0000000000..938860e758 --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.tsx @@ -0,0 +1,28 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { defineExtension } from './extension' +import UserMenuDynamic from './user-menu-dynamic' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts new file mode 100644 index 0000000000..ff2c40b104 --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts new file mode 100644 index 0000000000..bd8bc313e2 --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts @@ -0,0 +1,42 @@ +import { createEffect, createSignal } from 'solid-js' + +import type { User } from '../../sample/sample-query-users' +import { queryUsers } from '../../sample/sample-query-users' + +/** + * Simulate a user searching with some delay. + */ +export function useUserQuery( + getQuery: () => string, + getEnabled: () => boolean, +) { + const [users, setUsers] = createSignal([]) + const [loading, setLoading] = createSignal(true) + + createEffect(() => { + const query = getQuery() + const enabled = getEnabled() + + if (!enabled) { + setUsers([]) + return + } + + setLoading(true) + let cancelled = false + + void queryUsers(query).then((filteredUsers) => { + if (cancelled) { + return + } + setUsers(filteredUsers) + setLoading(false) + }) + + return () => { + cancelled = true + } + }) + + return { loading, users } +} diff --git a/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx new file mode 100644 index 0000000000..a9d721e501 --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.tsx @@ -0,0 +1,21 @@ +import { createSignal, type JSX } from 'solid-js' + +import { UserMenu } from '../../ui/user-menu' + +import { useUserQuery } from './use-user-query' + +export default function UserMenuDynamic(): JSX.Element { + const [query, setQuery] = createSignal('') + const [open, setOpen] = createSignal(false) + + const { loading, users } = useUserQuery(query, open) + + return ( + + ) +} diff --git a/solid-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/solid-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts new file mode 100644 index 0000000000..ab78fd5525 --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts @@ -0,0 +1,40 @@ +import { users } from './sample-user-data' + +export interface User { + id: number + name: string +} + +const connectHandlers: VoidFunction[] = [] +let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' + +/** + * A utility function to simulate different network states. Useful for testing. + * + * @internal + */ +export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { + networkStatus = status + if (status !== 'offline') { + connectHandlers.forEach((handler) => handler()) + connectHandlers.length = 0 + } +} + +/** + * Simulate a user searching with some delay. + */ +export async function queryUsers(query: string): Promise { + if (networkStatus === 'offline') { + await new Promise((resolve) => connectHandlers.push(resolve)) + } + if (networkStatus === 'slow') { + await new Promise((resolve) => setTimeout(resolve, 300)) + } + + const normalizedQuery = query.toLowerCase().trim() + const filteredUsers = users + .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) + .slice(0, 10) + return filteredUsers +} diff --git a/solid-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/solid-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/solid-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/solid-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/solid-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx b/solid-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..61d3cd96d8 --- /dev/null +++ b/solid-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,64 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/solid' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/solid/autocomplete' +import { For, type JSX } from 'solid-js' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}): JSX.Element { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor().commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor().commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + + {(user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + )} + +
+
+
+
+ ) +} diff --git a/solid-user-menu-dynamic/src/index.tsx b/solid-user-menu-dynamic/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-user-menu-dynamic/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-user-menu-dynamic/tsconfig.app.json b/solid-user-menu-dynamic/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-user-menu-dynamic/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-user-menu-dynamic/tsconfig.json b/solid-user-menu-dynamic/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-user-menu-dynamic/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-user-menu-dynamic/tsconfig.node.json b/solid-user-menu-dynamic/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-user-menu-dynamic/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-user-menu-dynamic/vite.config.ts b/solid-user-menu-dynamic/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-user-menu-dynamic/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-user-menu/.gitignore b/solid-user-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-user-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-user-menu/README.md b/solid-user-menu/README.md new file mode 100644 index 0000000000..51f890d5bb --- /dev/null +++ b/solid-user-menu/README.md @@ -0,0 +1,15 @@ +# solid-user-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-user-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-user-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-user-menu solid-user-menu +cd solid-user-menu +npm install +npm run dev +``` diff --git a/solid-user-menu/index.html b/solid-user-menu/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-user-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-user-menu/package.json b/solid-user-menu/package.json new file mode 100644 index 0000000000..5b2e08ee99 --- /dev/null +++ b/solid-user-menu/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-user-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-user-menu/src/App.tsx b/solid-user-menu/src/App.tsx new file mode 100644 index 0000000000..92fca03d42 --- /dev/null +++ b/solid-user-menu/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/user-menu' + +export default function App() { + return +} diff --git a/solid-user-menu/src/app.css b/solid-user-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-user-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-user-menu/src/components/editor/examples/user-menu/editor.tsx b/solid-user-menu/src/components/editor/examples/user-menu/editor.tsx new file mode 100644 index 0000000000..30fee3d379 --- /dev/null +++ b/solid-user-menu/src/components/editor/examples/user-menu/editor.tsx @@ -0,0 +1,33 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { tags } from '../../sample/sample-tag-data' +import { users } from '../../sample/sample-user-data' +import { TagMenu } from '../../ui/tag-menu' +import { UserMenu } from '../../ui/user-menu' + +import { defineExtension } from './extension' + +export default function Editor(): JSX.Element { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return ( + +
+
+
+ + +
+
+
+ ) +} diff --git a/solid-user-menu/src/components/editor/examples/user-menu/extension.ts b/solid-user-menu/src/components/editor/examples/user-menu/extension.ts new file mode 100644 index 0000000000..56a97a4779 --- /dev/null +++ b/solid-user-menu/src/components/editor/examples/user-menu/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone or # to tag something...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-user-menu/src/components/editor/examples/user-menu/index.ts b/solid-user-menu/src/components/editor/examples/user-menu/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-user-menu/src/components/editor/examples/user-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-user-menu/src/components/editor/sample/sample-tag-data.ts b/solid-user-menu/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/solid-user-menu/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/solid-user-menu/src/components/editor/sample/sample-user-data.ts b/solid-user-menu/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/solid-user-menu/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/solid-user-menu/src/components/editor/ui/tag-menu/index.ts b/solid-user-menu/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..d344b33a70 --- /dev/null +++ b/solid-user-menu/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu' diff --git a/solid-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx b/solid-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx new file mode 100644 index 0000000000..03e3534da3 --- /dev/null +++ b/solid-user-menu/src/components/editor/ui/tag-menu/tag-menu.tsx @@ -0,0 +1,54 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/solid' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/solid/autocomplete' +import { For, type JSX } from 'solid-js' + +const regex = /#[\da-z]*$/i + +export default function TagMenu(props: { + tags: { id: number; label: string }[] +}): JSX.Element { + const editor = useEditor>() + + const handleTagInsert = (id: number, label: string) => { + editor().commands.insertMention({ + id: id.toString(), + value: '#' + label, + kind: 'tag', + }) + editor().commands.insertText({ text: ' ' }) + } + + return ( + + + +
+ + No results + + + + {(tag) => ( + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + )} + +
+
+
+
+ ) +} diff --git a/solid-user-menu/src/components/editor/ui/user-menu/index.ts b/solid-user-menu/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..f30e75d5da --- /dev/null +++ b/solid-user-menu/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu' diff --git a/solid-user-menu/src/components/editor/ui/user-menu/user-menu.tsx b/solid-user-menu/src/components/editor/ui/user-menu/user-menu.tsx new file mode 100644 index 0000000000..61d3cd96d8 --- /dev/null +++ b/solid-user-menu/src/components/editor/ui/user-menu/user-menu.tsx @@ -0,0 +1,64 @@ +import type { BasicExtension } from 'prosekit/basic' +import { canUseRegexLookbehind, type Union } from 'prosekit/core' +import type { MentionExtension } from 'prosekit/extensions/mention' +import { useEditor } from 'prosekit/solid' +import { + AutocompleteEmpty, + AutocompleteItem, + AutocompletePopup, + AutocompletePositioner, + AutocompleteRoot, +} from 'prosekit/solid/autocomplete' +import { For, type JSX } from 'solid-js' + +// Match inputs like "@", "@foo", "@foo bar" etc. Do not match "@ foo". +const regex = canUseRegexLookbehind() ? /(? void + onOpenChange?: (open: boolean) => void +}): JSX.Element { + const editor = useEditor>() + + const handleUserInsert = (id: number, username: string) => { + editor().commands.insertMention({ + id: id.toString(), + value: '@' + username, + kind: 'user', + }) + editor().commands.insertText({ text: ' ' }) + } + + return ( + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} + > + + +
+ + {props.loading ? 'Loading...' : 'No results'} + + + + {(user) => ( + handleUserInsert(user.id, user.name)} + > + + {user.name} + + + )} + +
+
+
+
+ ) +} diff --git a/solid-user-menu/src/index.tsx b/solid-user-menu/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-user-menu/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-user-menu/tsconfig.app.json b/solid-user-menu/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-user-menu/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-user-menu/tsconfig.json b/solid-user-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-user-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-user-menu/tsconfig.node.json b/solid-user-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-user-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-user-menu/vite.config.ts b/solid-user-menu/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-user-menu/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-word-counter/.gitignore b/solid-word-counter/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-word-counter/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-word-counter/README.md b/solid-word-counter/README.md new file mode 100644 index 0000000000..d7f1e4743f --- /dev/null +++ b/solid-word-counter/README.md @@ -0,0 +1,15 @@ +# solid-word-counter + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-word-counter) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-word-counter) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-word-counter solid-word-counter +cd solid-word-counter +npm install +npm run dev +``` diff --git a/solid-word-counter/index.html b/solid-word-counter/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-word-counter/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-word-counter/package.json b/solid-word-counter/package.json new file mode 100644 index 0000000000..48f953f7e6 --- /dev/null +++ b/solid-word-counter/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-solid-word-counter", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-word-counter/src/App.tsx b/solid-word-counter/src/App.tsx new file mode 100644 index 0000000000..9da98dddb5 --- /dev/null +++ b/solid-word-counter/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/word-counter' + +export default function App() { + return +} diff --git a/solid-word-counter/src/app.css b/solid-word-counter/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-word-counter/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-word-counter/src/components/editor/examples/word-counter/editor.tsx b/solid-word-counter/src/components/editor/examples/word-counter/editor.tsx new file mode 100644 index 0000000000..84b8e69273 --- /dev/null +++ b/solid-word-counter/src/components/editor/examples/word-counter/editor.tsx @@ -0,0 +1,35 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor, type NodeJSON } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +import { sampleContent } from '../../sample/sample-doc-word-counter' +import { WordCounter } from '../../ui/word-counter' + +import { defineExtension } from './extension' + +interface EditorProps { + initialContent?: NodeJSON +} + +export default function Editor(props: EditorProps): JSX.Element { + const defaultContent = props.initialContent ?? sampleContent + const extension = defineExtension() + const editor = createEditor({ extension, defaultContent }) + + return ( + +
+
+
+ +
+
+
+ ) +} diff --git a/solid-word-counter/src/components/editor/examples/word-counter/extension.ts b/solid-word-counter/src/components/editor/examples/word-counter/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/solid-word-counter/src/components/editor/examples/word-counter/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/solid-word-counter/src/components/editor/examples/word-counter/index.ts b/solid-word-counter/src/components/editor/examples/word-counter/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-word-counter/src/components/editor/examples/word-counter/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/solid-word-counter/src/components/editor/sample/sample-doc-word-counter.ts new file mode 100644 index 0000000000..0b5d435038 --- /dev/null +++ b/solid-word-counter/src/components/editor/sample/sample-doc-word-counter.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Start typing and observe the word count update below.', + }, + ], + }, + ], +} diff --git a/solid-word-counter/src/components/editor/ui/word-counter/index.ts b/solid-word-counter/src/components/editor/ui/word-counter/index.ts new file mode 100644 index 0000000000..929ee3e41a --- /dev/null +++ b/solid-word-counter/src/components/editor/ui/word-counter/index.ts @@ -0,0 +1 @@ +export { default as WordCounter } from './word-counter' diff --git a/solid-word-counter/src/components/editor/ui/word-counter/word-counter.tsx b/solid-word-counter/src/components/editor/ui/word-counter/word-counter.tsx new file mode 100644 index 0000000000..bb527a1897 --- /dev/null +++ b/solid-word-counter/src/components/editor/ui/word-counter/word-counter.tsx @@ -0,0 +1,23 @@ +import type { Editor } from 'prosekit/core' +import { useEditorDerivedValue } from 'prosekit/solid' +import type { JSX } from 'solid-js' + +function getWordCount(editor: Editor) { + const doc = editor.state.doc + const words = doc ? doc.textBetween(0, doc.content.size, ' ') : '' + const wordCount = words.split(/\s+/).filter((s) => s).length + const characterCount = doc ? doc.textContent.length : 0 + return { wordCount, characterCount } +} + +export default function WordCounter(): JSX.Element { + const counts = useEditorDerivedValue(getWordCount) + + return ( +
+ Word Count: {counts().wordCount} +
+ Character Count: {counts().characterCount} +
+ ) +} diff --git a/solid-word-counter/src/index.tsx b/solid-word-counter/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-word-counter/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-word-counter/tsconfig.app.json b/solid-word-counter/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-word-counter/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-word-counter/tsconfig.json b/solid-word-counter/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-word-counter/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-word-counter/tsconfig.node.json b/solid-word-counter/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-word-counter/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-word-counter/vite.config.ts b/solid-word-counter/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-word-counter/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/solid-yjs/.gitignore b/solid-yjs/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/solid-yjs/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/solid-yjs/README.md b/solid-yjs/README.md new file mode 100644 index 0000000000..7277cc063f --- /dev/null +++ b/solid-yjs/README.md @@ -0,0 +1,15 @@ +# solid-yjs + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/solid-yjs) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/solid-yjs) + +Run the example locally with: + +```bash +npx degit prosekit/examples/solid-yjs solid-yjs +cd solid-yjs +npm install +npm run dev +``` diff --git a/solid-yjs/index.html b/solid-yjs/index.html new file mode 100644 index 0000000000..375ea8dbc4 --- /dev/null +++ b/solid-yjs/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Solid + + +
+ + + diff --git a/solid-yjs/package.json b/solid-yjs/package.json new file mode 100644 index 0000000000..7f3eac83d9 --- /dev/null +++ b/solid-yjs/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-solid-yjs", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "solid-js": "^1.9.13", + "y-prosemirror": "^1.3.7", + "y-websocket": "^3.0.0", + "yjs": "^13.6.30" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-solid": "^2.11.12" + } +} diff --git a/solid-yjs/src/App.tsx b/solid-yjs/src/App.tsx new file mode 100644 index 0000000000..8641aefe47 --- /dev/null +++ b/solid-yjs/src/App.tsx @@ -0,0 +1,5 @@ +import { ExampleEditor } from './components/editor/examples/yjs' + +export default function App() { + return +} diff --git a/solid-yjs/src/app.css b/solid-yjs/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/solid-yjs/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/solid-yjs/src/components/editor/examples/yjs/editor-component.tsx b/solid-yjs/src/components/editor/examples/yjs/editor-component.tsx new file mode 100644 index 0000000000..6661dac8c8 --- /dev/null +++ b/solid-yjs/src/components/editor/examples/yjs/editor-component.tsx @@ -0,0 +1,41 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' +import 'prosekit/extensions/yjs/style.css' + +import { createEditor } from 'prosekit/core' +import { ProseKit } from 'prosekit/solid' +import { createMemo, type JSX } from 'solid-js' +import { WebsocketProvider } from 'y-websocket' +import * as Y from 'yjs' + +import { Toolbar } from '../../ui/toolbar' + +import { defineExtension } from './extension' + +export default function EditorComponent(props: { room?: string }): JSX.Element { + const editor = createMemo(() => { + const doc = new Y.Doc() + const provider = new WebsocketProvider( + 'wss://demos.yjs.dev/ws', + `github.com/prosekit/room_${props.room}`, + doc, + ) + + const extension = defineExtension(doc, provider.awareness) + return createEditor({ extension }) + }) + + return ( + +
+ +
+
+
+
+
+ ) +} diff --git a/solid-yjs/src/components/editor/examples/yjs/editor.tsx b/solid-yjs/src/components/editor/examples/yjs/editor.tsx new file mode 100644 index 0000000000..a047471e66 --- /dev/null +++ b/solid-yjs/src/components/editor/examples/yjs/editor.tsx @@ -0,0 +1,14 @@ +import { createSignal, type JSX } from 'solid-js' + +import EditorComponent from './editor-component' + +export default function Editor(): JSX.Element { + const [room] = createSignal(Math.random().toString(36).substring(2, 15)) + + return ( +
+ + +
+ ) +} diff --git a/solid-yjs/src/components/editor/examples/yjs/extension.ts b/solid-yjs/src/components/editor/examples/yjs/extension.ts new file mode 100644 index 0000000000..b2546b126e --- /dev/null +++ b/solid-yjs/src/components/editor/examples/yjs/extension.ts @@ -0,0 +1,48 @@ +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' +import { defineYjs } from 'prosekit/extensions/yjs' +import type { Awareness } from 'prosekit/extensions/yjs' +import type * as Y from 'yjs' + +export function defineExtension(doc: Y.Doc, awareness: Awareness) { + return union( + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineYjs({ doc, awareness }), + ) +} + +export type EditorExtension = ReturnType diff --git a/solid-yjs/src/components/editor/examples/yjs/index.ts b/solid-yjs/src/components/editor/examples/yjs/index.ts new file mode 100644 index 0000000000..1a07a6017a --- /dev/null +++ b/solid-yjs/src/components/editor/examples/yjs/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor' diff --git a/solid-yjs/src/components/editor/ui/button/button.tsx b/solid-yjs/src/components/editor/ui/button/button.tsx new file mode 100644 index 0000000000..a1b2e44b0c --- /dev/null +++ b/solid-yjs/src/components/editor/ui/button/button.tsx @@ -0,0 +1,42 @@ +import { + TooltipPopup, + TooltipPositioner, + TooltipRoot, + TooltipTrigger, +} from 'prosekit/solid/tooltip' +import type { JSX } from 'solid-js' + +export default function Button(props: { + pressed?: boolean + disabled?: boolean + onClick?: () => void + tooltip?: string + children: JSX.Element +}): JSX.Element { + return ( + + + + + {props.tooltip ? ( + + + {props.tooltip} + + + ) : null} + + ) +} diff --git a/solid-yjs/src/components/editor/ui/button/index.ts b/solid-yjs/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..9743944eda --- /dev/null +++ b/solid-yjs/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button' diff --git a/solid-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx b/solid-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx new file mode 100644 index 0000000000..efa306305f --- /dev/null +++ b/solid-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.tsx @@ -0,0 +1,137 @@ +import type { Uploader } from 'prosekit/extensions/file' +import type { ImageExtension } from 'prosekit/extensions/image' +import { useEditor } from 'prosekit/solid' +import { + PopoverPopup, + PopoverPositioner, + PopoverRoot, + PopoverTrigger, +} from 'prosekit/solid/popover' +import type { OpenChangeEvent } from 'prosekit/web/popover' +import { createSignal, createUniqueId, Show, type JSX } from 'solid-js' + +import { Button } from '../button' + +export default function ImageUploadPopover(props: { + uploader: Uploader + tooltip: string + disabled: boolean + children: JSX.Element +}): JSX.Element { + const [open, setOpen] = createSignal(false) + const [url, setUrl] = createSignal('') + const [file, setFile] = createSignal(null) + const ariaId = createUniqueId() + + const editor = useEditor() + + const handleFileChange = (event: Event) => { + const target = event.target as HTMLInputElement + const selectedFile = target.files?.[0] + + if (selectedFile) { + setFile(selectedFile) + setUrl('') + } else { + setFile(null) + } + } + + const handleUrlChange = (event: Event) => { + const target = event.target as HTMLInputElement + const inputUrl = target.value + + if (inputUrl) { + setUrl(inputUrl) + setFile(null) + } else { + setUrl('') + } + } + + const deferResetState = () => { + setTimeout(() => { + setUrl('') + setFile(null) + }, 300) + } + + const handleSubmit = () => { + if (url()) { + editor().commands.insertImage({ src: url() }) + } else if (file()) { + editor().commands.uploadImage({ file: file()!, uploader: props.uploader }) + } + setOpen(false) + deferResetState() + } + + const handleOpenChange = (event: OpenChangeEvent) => { + if (!event.detail) { + deferResetState() + } + setOpen(event.detail) + } + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/solid-yjs/src/components/editor/ui/image-upload-popover/index.ts b/solid-yjs/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..5d49d873ce --- /dev/null +++ b/solid-yjs/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover' diff --git a/solid-yjs/src/components/editor/ui/toolbar/index.ts b/solid-yjs/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..fdf6741e6a --- /dev/null +++ b/solid-yjs/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar' diff --git a/solid-yjs/src/components/editor/ui/toolbar/toolbar.tsx b/solid-yjs/src/components/editor/ui/toolbar/toolbar.tsx new file mode 100644 index 0000000000..ee3858791a --- /dev/null +++ b/solid-yjs/src/components/editor/ui/toolbar/toolbar.tsx @@ -0,0 +1,406 @@ +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import type { Uploader } from 'prosekit/extensions/file' +import { useEditorDerivedValue } from 'prosekit/solid' +import { Show, type JSX } from 'solid-js' + +import { Button } from '../button' +import { ImageUploadPopover } from '../image-upload-popover' + +function getToolbarItems(editor: Editor) { + return { + undo: editor.commands.undo + ? { + isActive: false, + canExec: editor.commands.undo.canExec(), + command: () => editor.commands.undo(), + } + : undefined, + redo: editor.commands.redo + ? { + isActive: false, + canExec: editor.commands.redo.canExec(), + command: () => editor.commands.redo(), + } + : undefined, + bold: editor.commands.toggleBold + ? { + isActive: editor.marks.bold.isActive(), + canExec: editor.commands.toggleBold.canExec(), + command: () => editor.commands.toggleBold(), + } + : undefined, + italic: editor.commands.toggleItalic + ? { + isActive: editor.marks.italic.isActive(), + canExec: editor.commands.toggleItalic.canExec(), + command: () => editor.commands.toggleItalic(), + } + : undefined, + underline: editor.commands.toggleUnderline + ? { + isActive: editor.marks.underline.isActive(), + canExec: editor.commands.toggleUnderline.canExec(), + command: () => editor.commands.toggleUnderline(), + } + : undefined, + strike: editor.commands.toggleStrike + ? { + isActive: editor.marks.strike.isActive(), + canExec: editor.commands.toggleStrike.canExec(), + command: () => editor.commands.toggleStrike(), + } + : undefined, + code: editor.commands.toggleCode + ? { + isActive: editor.marks.code.isActive(), + canExec: editor.commands.toggleCode.canExec(), + command: () => editor.commands.toggleCode(), + } + : undefined, + codeBlock: editor.commands.insertCodeBlock + ? { + isActive: editor.nodes.codeBlock.isActive(), + canExec: editor.commands.insertCodeBlock.canExec({ + language: 'javascript', + }), + command: () => + editor.commands.insertCodeBlock({ language: 'javascript' }), + } + : undefined, + heading1: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 1 }), + canExec: editor.commands.toggleHeading.canExec({ level: 1 }), + command: () => editor.commands.toggleHeading({ level: 1 }), + } + : undefined, + heading2: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 2 }), + canExec: editor.commands.toggleHeading.canExec({ level: 2 }), + command: () => editor.commands.toggleHeading({ level: 2 }), + } + : undefined, + heading3: editor.commands.toggleHeading + ? { + isActive: editor.nodes.heading.isActive({ level: 3 }), + canExec: editor.commands.toggleHeading.canExec({ level: 3 }), + command: () => editor.commands.toggleHeading({ level: 3 }), + } + : undefined, + horizontalRule: editor.commands.insertHorizontalRule + ? { + isActive: editor.nodes.horizontalRule.isActive(), + canExec: editor.commands.insertHorizontalRule.canExec(), + command: () => editor.commands.insertHorizontalRule(), + } + : undefined, + blockquote: editor.commands.toggleBlockquote + ? { + isActive: editor.nodes.blockquote.isActive(), + canExec: editor.commands.toggleBlockquote.canExec(), + command: () => editor.commands.toggleBlockquote(), + } + : undefined, + bulletList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'bullet' }), + canExec: editor.commands.toggleList.canExec({ kind: 'bullet' }), + command: () => editor.commands.toggleList({ kind: 'bullet' }), + } + : undefined, + orderedList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'ordered' }), + canExec: editor.commands.toggleList.canExec({ kind: 'ordered' }), + command: () => editor.commands.toggleList({ kind: 'ordered' }), + } + : undefined, + taskList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'task' }), + canExec: editor.commands.toggleList.canExec({ kind: 'task' }), + command: () => editor.commands.toggleList({ kind: 'task' }), + } + : undefined, + toggleList: editor.commands.toggleList + ? { + isActive: editor.nodes.list.isActive({ kind: 'toggle' }), + canExec: editor.commands.toggleList.canExec({ kind: 'toggle' }), + command: () => editor.commands.toggleList({ kind: 'toggle' }), + } + : undefined, + indentList: editor.commands.indentList + ? { + isActive: false, + canExec: editor.commands.indentList.canExec(), + command: () => editor.commands.indentList(), + } + : undefined, + dedentList: editor.commands.dedentList + ? { + isActive: false, + canExec: editor.commands.dedentList.canExec(), + command: () => editor.commands.dedentList(), + } + : undefined, + insertImage: editor.commands.insertImage + ? { + isActive: false, + canExec: editor.commands.insertImage.canExec(), + } + : undefined, + } +} + +export default function Toolbar(props: { + uploader?: Uploader +}): JSX.Element { + const items = useEditorDerivedValue(getToolbarItems) + + return ( +
+ + {(item) => ( + + )} + + + {(item) => ( + + )} + + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + + )} + + + {(item) => ( + +
+ + )} + +
+ ) +} diff --git a/solid-yjs/src/index.tsx b/solid-yjs/src/index.tsx new file mode 100644 index 0000000000..92b7740757 --- /dev/null +++ b/solid-yjs/src/index.tsx @@ -0,0 +1,8 @@ +/* @refresh reload */ +import './app.css' +import { render } from 'solid-js/web' +import App from './App' + +const root = document.getElementById('root') + +render(() => , root!) diff --git a/solid-yjs/tsconfig.app.json b/solid-yjs/tsconfig.app.json new file mode 100644 index 0000000000..c0b480e758 --- /dev/null +++ b/solid-yjs/tsconfig.app.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/solid-yjs/tsconfig.json b/solid-yjs/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/solid-yjs/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/solid-yjs/tsconfig.node.json b/solid-yjs/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/solid-yjs/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/solid-yjs/vite.config.ts b/solid-yjs/vite.config.ts new file mode 100644 index 0000000000..9cb3cb51fd --- /dev/null +++ b/solid-yjs/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import solid from 'vite-plugin-solid' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [solid(), tailwindcss()], +}) diff --git a/svelte-block-handle/.gitignore b/svelte-block-handle/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-block-handle/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-block-handle/README.md b/svelte-block-handle/README.md new file mode 100644 index 0000000000..dcf3b1238c --- /dev/null +++ b/svelte-block-handle/README.md @@ -0,0 +1,15 @@ +# svelte-block-handle + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-block-handle) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-block-handle) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-block-handle svelte-block-handle +cd svelte-block-handle +npm install +npm run dev +``` diff --git a/svelte-block-handle/index.html b/svelte-block-handle/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-block-handle/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-block-handle/package.json b/svelte-block-handle/package.json new file mode 100644 index 0000000000..3c732dd7bd --- /dev/null +++ b/svelte-block-handle/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-block-handle", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-block-handle/src/App.svelte b/svelte-block-handle/src/App.svelte new file mode 100644 index 0000000000..3d9f1706f0 --- /dev/null +++ b/svelte-block-handle/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-block-handle/src/app.css b/svelte-block-handle/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-block-handle/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-block-handle/src/components/editor/examples/block-handle/editor.svelte b/svelte-block-handle/src/components/editor/examples/block-handle/editor.svelte new file mode 100644 index 0000000000..4d5fa066df --- /dev/null +++ b/svelte-block-handle/src/components/editor/examples/block-handle/editor.svelte @@ -0,0 +1,32 @@ + + + +
+
+
+ + +
+
+
diff --git a/svelte-block-handle/src/components/editor/examples/block-handle/extension.ts b/svelte-block-handle/src/components/editor/examples/block-handle/extension.ts new file mode 100644 index 0000000000..b5686b8c04 --- /dev/null +++ b/svelte-block-handle/src/components/editor/examples/block-handle/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union(defineBasicExtension(), defineCodeBlockView()) +} + +export type EditorExtension = ReturnType diff --git a/svelte-block-handle/src/components/editor/examples/block-handle/index.ts b/svelte-block-handle/src/components/editor/examples/block-handle/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-block-handle/src/components/editor/examples/block-handle/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/svelte-block-handle/src/components/editor/sample/sample-doc-block-handle.ts new file mode 100644 index 0000000000..3c6ccdc203 --- /dev/null +++ b/svelte-block-handle/src/components/editor/sample/sample-doc-block-handle.ts @@ -0,0 +1,323 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Drag and Drop Demo', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Getting Started', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This paragraph can be moved above or below other blocks.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Different Block Types', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'You can drag paragraphs, headings, lists, code blocks, and more.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Lists Work Too', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This entire list can be dragged', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Individual list items stay together', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try moving this list around', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Ordered lists also support dragging', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The numbering updates automatically', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag this list to see it in action', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Even code blocks can be moved:', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: 'javascript', + }, + content: [ + { + type: 'text', + text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Nested Content', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This blockquote can be moved as a single unit.', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested blockquotes move together with their parent.', + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Try It Yourself', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Practice by moving this paragraph to the top of the document.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Or drag this one to between the headings above.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The drag handles make it easy to reorganize your content exactly how you want it.', + }, + ], + }, + ], +} diff --git a/svelte-block-handle/src/components/editor/ui/block-handle/block-handle.svelte b/svelte-block-handle/src/components/editor/ui/block-handle/block-handle.svelte new file mode 100644 index 0000000000..f67e42dc91 --- /dev/null +++ b/svelte-block-handle/src/components/editor/ui/block-handle/block-handle.svelte @@ -0,0 +1,28 @@ + + + + + + +
+
+ +
+
+
+
+
diff --git a/svelte-block-handle/src/components/editor/ui/block-handle/index.ts b/svelte-block-handle/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..6d21191384 --- /dev/null +++ b/svelte-block-handle/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.svelte' diff --git a/svelte-block-handle/src/components/editor/ui/code-block-view/code-block-view.svelte b/svelte-block-handle/src/components/editor/ui/code-block-view/code-block-view.svelte new file mode 100644 index 0000000000..aaa4617fc1 --- /dev/null +++ b/svelte-block-handle/src/components/editor/ui/code-block-view/code-block-view.svelte @@ -0,0 +1,40 @@ + + + +

diff --git a/svelte-block-handle/src/components/editor/ui/code-block-view/index.ts b/svelte-block-handle/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..eb54b2f6d9
--- /dev/null
+++ b/svelte-block-handle/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSvelteNodeView,
+  type SvelteNodeViewComponent,
+} from 'prosekit/svelte'
+
+import CodeBlockView from './code-block-view.svelte'
+
+export function defineCodeBlockView(): Extension {
+  return defineSvelteNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView as SvelteNodeViewComponent,
+  })
+}
diff --git a/svelte-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/svelte-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.svelte
new file mode 100644
index 0000000000..7f6cac1db0
--- /dev/null
+++ b/svelte-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.svelte
@@ -0,0 +1,5 @@
+
+
+
diff --git a/svelte-block-handle/src/components/editor/ui/drop-indicator/index.ts b/svelte-block-handle/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..06e89357ed
--- /dev/null
+++ b/svelte-block-handle/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator.svelte'
diff --git a/svelte-block-handle/src/main.ts b/svelte-block-handle/src/main.ts
new file mode 100644
index 0000000000..b4bc565380
--- /dev/null
+++ b/svelte-block-handle/src/main.ts
@@ -0,0 +1,8 @@
+import './app.css'
+
+import { mount } from 'svelte'
+import App from './App.svelte'
+
+const app = mount(App, { target: document.getElementById('app')! })
+
+export default app
diff --git a/svelte-block-handle/src/vite-env.d.ts b/svelte-block-handle/src/vite-env.d.ts
new file mode 100644
index 0000000000..4078e7476a
--- /dev/null
+++ b/svelte-block-handle/src/vite-env.d.ts
@@ -0,0 +1,2 @@
+/// 
+/// 
diff --git a/svelte-block-handle/svelte.config.js b/svelte-block-handle/svelte.config.js
new file mode 100644
index 0000000000..b0683fd24d
--- /dev/null
+++ b/svelte-block-handle/svelte.config.js
@@ -0,0 +1,7 @@
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
+
+export default {
+  // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
+  // for more information about preprocessors
+  preprocess: vitePreprocess(),
+}
diff --git a/svelte-block-handle/tsconfig.json b/svelte-block-handle/tsconfig.json
new file mode 100644
index 0000000000..86876593dd
--- /dev/null
+++ b/svelte-block-handle/tsconfig.json
@@ -0,0 +1,21 @@
+{
+  "extends": "@tsconfig/svelte/tsconfig.json",
+  "compilerOptions": {
+    "target": "ESNext",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "resolveJsonModule": true,
+    /**
+     * Typecheck JS in `.svelte` and `.js` files by default.
+     * Disable checkJs if you'd like to use dynamic types in JS.
+     * Note that setting allowJs false does not prevent the use
+     * of JS in `.svelte` files.
+     */
+    "allowJs": true,
+    "checkJs": true,
+    "allowImportingTsExtensions": true,
+    "isolatedModules": true
+  },
+  "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
+  "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/svelte-block-handle/tsconfig.node.json b/svelte-block-handle/tsconfig.node.json
new file mode 100644
index 0000000000..494bfe0835
--- /dev/null
+++ b/svelte-block-handle/tsconfig.node.json
@@ -0,0 +1,9 @@
+{
+  "compilerOptions": {
+    "composite": true,
+    "skipLibCheck": true,
+    "module": "ESNext",
+    "moduleResolution": "bundler"
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/svelte-block-handle/vite.config.ts b/svelte-block-handle/vite.config.ts
new file mode 100644
index 0000000000..11edea7f23
--- /dev/null
+++ b/svelte-block-handle/vite.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import { svelte } from '@sveltejs/vite-plugin-svelte'
+import tailwindcss from '@tailwindcss/vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [svelte(), tailwindcss()],
+})
diff --git a/svelte-blockquote/.gitignore b/svelte-blockquote/.gitignore
new file mode 100644
index 0000000000..5d6225c6df
--- /dev/null
+++ b/svelte-blockquote/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+.next
+.svelte-kit
diff --git a/svelte-blockquote/README.md b/svelte-blockquote/README.md
new file mode 100644
index 0000000000..06c1bd959c
--- /dev/null
+++ b/svelte-blockquote/README.md
@@ -0,0 +1,15 @@
+# svelte-blockquote
+
+A [ProseKit](https://prosekit.dev) example.
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-blockquote)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-blockquote)
+
+Run the example locally with:
+
+```bash
+npx degit prosekit/examples/svelte-blockquote svelte-blockquote
+cd svelte-blockquote
+npm install
+npm run dev
+```
diff --git a/svelte-blockquote/index.html b/svelte-blockquote/index.html
new file mode 100644
index 0000000000..58212c2501
--- /dev/null
+++ b/svelte-blockquote/index.html
@@ -0,0 +1,12 @@
+
+
+  
+    
+    
+    ProseKit + Svelte
+  
+  
+    
+ + + diff --git a/svelte-blockquote/package.json b/svelte-blockquote/package.json new file mode 100644 index 0000000000..1b2fc18838 --- /dev/null +++ b/svelte-blockquote/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-blockquote", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-blockquote/src/App.svelte b/svelte-blockquote/src/App.svelte new file mode 100644 index 0000000000..29b9c5ff97 --- /dev/null +++ b/svelte-blockquote/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-blockquote/src/app.css b/svelte-blockquote/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-blockquote/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-blockquote/src/components/editor/examples/blockquote/editor.svelte b/svelte-blockquote/src/components/editor/examples/blockquote/editor.svelte new file mode 100644 index 0000000000..741b836c3c --- /dev/null +++ b/svelte-blockquote/src/components/editor/examples/blockquote/editor.svelte @@ -0,0 +1,23 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-blockquote/src/components/editor/examples/blockquote/extension.ts b/svelte-blockquote/src/components/editor/examples/blockquote/extension.ts new file mode 100644 index 0000000000..5292b59e35 --- /dev/null +++ b/svelte-blockquote/src/components/editor/examples/blockquote/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBlockquote(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-blockquote/src/components/editor/examples/blockquote/index.ts b/svelte-blockquote/src/components/editor/examples/blockquote/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-blockquote/src/components/editor/examples/blockquote/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-blockquote/src/components/editor/ui/button/button.svelte b/svelte-blockquote/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-blockquote/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-blockquote/src/components/editor/ui/button/index.ts b/svelte-blockquote/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-blockquote/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/svelte-blockquote/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-blockquote/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-blockquote/src/components/editor/ui/toolbar/index.ts b/svelte-blockquote/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-blockquote/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-blockquote/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-blockquote/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-blockquote/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-blockquote/src/main.ts b/svelte-blockquote/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-blockquote/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-blockquote/src/vite-env.d.ts b/svelte-blockquote/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-blockquote/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-blockquote/svelte.config.js b/svelte-blockquote/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-blockquote/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-blockquote/tsconfig.json b/svelte-blockquote/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-blockquote/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-blockquote/tsconfig.node.json b/svelte-blockquote/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-blockquote/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-blockquote/vite.config.ts b/svelte-blockquote/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-blockquote/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-bold/.gitignore b/svelte-bold/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-bold/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-bold/README.md b/svelte-bold/README.md new file mode 100644 index 0000000000..d8c4f03064 --- /dev/null +++ b/svelte-bold/README.md @@ -0,0 +1,15 @@ +# svelte-bold + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-bold) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-bold) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-bold svelte-bold +cd svelte-bold +npm install +npm run dev +``` diff --git a/svelte-bold/index.html b/svelte-bold/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-bold/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-bold/package.json b/svelte-bold/package.json new file mode 100644 index 0000000000..7c6bd584f0 --- /dev/null +++ b/svelte-bold/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-bold", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-bold/src/App.svelte b/svelte-bold/src/App.svelte new file mode 100644 index 0000000000..222bcdb5f6 --- /dev/null +++ b/svelte-bold/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-bold/src/app.css b/svelte-bold/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-bold/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-bold/src/components/editor/examples/bold/editor.svelte b/svelte-bold/src/components/editor/examples/bold/editor.svelte new file mode 100644 index 0000000000..e0601d8915 --- /dev/null +++ b/svelte-bold/src/components/editor/examples/bold/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-bold/src/components/editor/examples/bold/extension.ts b/svelte-bold/src/components/editor/examples/bold/extension.ts new file mode 100644 index 0000000000..eaa4fba721 --- /dev/null +++ b/svelte-bold/src/components/editor/examples/bold/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBold } from 'prosekit/extensions/bold' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBold(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-bold/src/components/editor/examples/bold/index.ts b/svelte-bold/src/components/editor/examples/bold/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-bold/src/components/editor/examples/bold/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-bold/src/components/editor/sample/sample-doc-bold.ts b/svelte-bold/src/components/editor/sample/sample-doc-bold.ts new file mode 100644 index 0000000000..09ed08daad --- /dev/null +++ b/svelte-bold/src/components/editor/sample/sample-doc-bold.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/svelte-bold/src/components/editor/ui/button/button.svelte b/svelte-bold/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-bold/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-bold/src/components/editor/ui/button/index.ts b/svelte-bold/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-bold/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-bold/src/components/editor/ui/image-upload-popover/index.ts b/svelte-bold/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-bold/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-bold/src/components/editor/ui/toolbar/index.ts b/svelte-bold/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-bold/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-bold/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-bold/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-bold/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-bold/src/main.ts b/svelte-bold/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-bold/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-bold/src/vite-env.d.ts b/svelte-bold/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-bold/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-bold/svelte.config.js b/svelte-bold/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-bold/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-bold/tsconfig.json b/svelte-bold/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-bold/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-bold/tsconfig.node.json b/svelte-bold/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-bold/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-bold/vite.config.ts b/svelte-bold/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-bold/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-change-tracking/.gitignore b/svelte-change-tracking/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-change-tracking/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-change-tracking/README.md b/svelte-change-tracking/README.md new file mode 100644 index 0000000000..38c01b55c9 --- /dev/null +++ b/svelte-change-tracking/README.md @@ -0,0 +1,15 @@ +# svelte-change-tracking + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-change-tracking) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-change-tracking) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-change-tracking svelte-change-tracking +cd svelte-change-tracking +npm install +npm run dev +``` diff --git a/svelte-change-tracking/index.html b/svelte-change-tracking/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-change-tracking/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-change-tracking/package.json b/svelte-change-tracking/package.json new file mode 100644 index 0000000000..6e55f1b1a7 --- /dev/null +++ b/svelte-change-tracking/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-change-tracking", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-change-tracking/src/App.svelte b/svelte-change-tracking/src/App.svelte new file mode 100644 index 0000000000..ea0c2b2b45 --- /dev/null +++ b/svelte-change-tracking/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-change-tracking/src/app.css b/svelte-change-tracking/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-change-tracking/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-diff.svelte b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-diff.svelte new file mode 100644 index 0000000000..b8871f656f --- /dev/null +++ b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-diff.svelte @@ -0,0 +1,28 @@ + + + +
+
+
+
+
+
diff --git a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-main.svelte b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-main.svelte new file mode 100644 index 0000000000..a46ea48604 --- /dev/null +++ b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor-main.svelte @@ -0,0 +1,34 @@ + + +{#key props.key} + +
+
+
+
+
+
+{/key} diff --git a/svelte-change-tracking/src/components/editor/examples/change-tracking/editor.svelte b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor.svelte new file mode 100644 index 0000000000..8e74f7510a --- /dev/null +++ b/svelte-change-tracking/src/components/editor/examples/change-tracking/editor.svelte @@ -0,0 +1,63 @@ + + +
+
+
+ +
+ +
+
+ {#each commits as commit (commit.id)} +
+
+ +
+
+ + {commit.date.toLocaleTimeString()} + + +
+
+ {/each} +
+
diff --git a/svelte-change-tracking/src/components/editor/examples/change-tracking/index.ts b/svelte-change-tracking/src/components/editor/examples/change-tracking/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-change-tracking/src/components/editor/examples/change-tracking/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-change-tracking/src/main.ts b/svelte-change-tracking/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-change-tracking/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-change-tracking/src/vite-env.d.ts b/svelte-change-tracking/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-change-tracking/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-change-tracking/svelte.config.js b/svelte-change-tracking/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-change-tracking/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-change-tracking/tsconfig.json b/svelte-change-tracking/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-change-tracking/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-change-tracking/tsconfig.node.json b/svelte-change-tracking/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-change-tracking/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-change-tracking/vite.config.ts b/svelte-change-tracking/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-change-tracking/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-code-block-themes/.gitignore b/svelte-code-block-themes/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-code-block-themes/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-code-block-themes/README.md b/svelte-code-block-themes/README.md new file mode 100644 index 0000000000..e35ce06d8a --- /dev/null +++ b/svelte-code-block-themes/README.md @@ -0,0 +1,15 @@ +# svelte-code-block-themes + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-code-block-themes) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-code-block-themes) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-code-block-themes svelte-code-block-themes +cd svelte-code-block-themes +npm install +npm run dev +``` diff --git a/svelte-code-block-themes/index.html b/svelte-code-block-themes/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-code-block-themes/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-code-block-themes/package.json b/svelte-code-block-themes/package.json new file mode 100644 index 0000000000..55fccc1765 --- /dev/null +++ b/svelte-code-block-themes/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-code-block-themes", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-code-block-themes/src/App.svelte b/svelte-code-block-themes/src/App.svelte new file mode 100644 index 0000000000..25547b27a9 --- /dev/null +++ b/svelte-code-block-themes/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-code-block-themes/src/app.css b/svelte-code-block-themes/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-code-block-themes/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/editor.svelte b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/editor.svelte new file mode 100644 index 0000000000..4a259bc074 --- /dev/null +++ b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts new file mode 100644 index 0000000000..b5686b8c04 --- /dev/null +++ b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union(defineBasicExtension(), defineCodeBlockView()) +} + +export type EditorExtension = ReturnType diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.svelte b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.svelte new file mode 100644 index 0000000000..c62d761fc2 --- /dev/null +++ b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.svelte @@ -0,0 +1,29 @@ + + + + diff --git a/svelte-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.svelte b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.svelte new file mode 100644 index 0000000000..a585851af0 --- /dev/null +++ b/svelte-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.svelte @@ -0,0 +1,7 @@ + + +
+ +
diff --git a/svelte-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/svelte-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/svelte-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/svelte-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.svelte b/svelte-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.svelte new file mode 100644 index 0000000000..aaa4617fc1 --- /dev/null +++ b/svelte-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.svelte @@ -0,0 +1,40 @@ + + + +

diff --git a/svelte-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/svelte-code-block-themes/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..eb54b2f6d9
--- /dev/null
+++ b/svelte-code-block-themes/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSvelteNodeView,
+  type SvelteNodeViewComponent,
+} from 'prosekit/svelte'
+
+import CodeBlockView from './code-block-view.svelte'
+
+export function defineCodeBlockView(): Extension {
+  return defineSvelteNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView as SvelteNodeViewComponent,
+  })
+}
diff --git a/svelte-code-block-themes/src/main.ts b/svelte-code-block-themes/src/main.ts
new file mode 100644
index 0000000000..b4bc565380
--- /dev/null
+++ b/svelte-code-block-themes/src/main.ts
@@ -0,0 +1,8 @@
+import './app.css'
+
+import { mount } from 'svelte'
+import App from './App.svelte'
+
+const app = mount(App, { target: document.getElementById('app')! })
+
+export default app
diff --git a/svelte-code-block-themes/src/vite-env.d.ts b/svelte-code-block-themes/src/vite-env.d.ts
new file mode 100644
index 0000000000..4078e7476a
--- /dev/null
+++ b/svelte-code-block-themes/src/vite-env.d.ts
@@ -0,0 +1,2 @@
+/// 
+/// 
diff --git a/svelte-code-block-themes/svelte.config.js b/svelte-code-block-themes/svelte.config.js
new file mode 100644
index 0000000000..b0683fd24d
--- /dev/null
+++ b/svelte-code-block-themes/svelte.config.js
@@ -0,0 +1,7 @@
+import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'
+
+export default {
+  // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
+  // for more information about preprocessors
+  preprocess: vitePreprocess(),
+}
diff --git a/svelte-code-block-themes/tsconfig.json b/svelte-code-block-themes/tsconfig.json
new file mode 100644
index 0000000000..86876593dd
--- /dev/null
+++ b/svelte-code-block-themes/tsconfig.json
@@ -0,0 +1,21 @@
+{
+  "extends": "@tsconfig/svelte/tsconfig.json",
+  "compilerOptions": {
+    "target": "ESNext",
+    "useDefineForClassFields": true,
+    "module": "ESNext",
+    "resolveJsonModule": true,
+    /**
+     * Typecheck JS in `.svelte` and `.js` files by default.
+     * Disable checkJs if you'd like to use dynamic types in JS.
+     * Note that setting allowJs false does not prevent the use
+     * of JS in `.svelte` files.
+     */
+    "allowJs": true,
+    "checkJs": true,
+    "allowImportingTsExtensions": true,
+    "isolatedModules": true
+  },
+  "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
+  "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/svelte-code-block-themes/tsconfig.node.json b/svelte-code-block-themes/tsconfig.node.json
new file mode 100644
index 0000000000..494bfe0835
--- /dev/null
+++ b/svelte-code-block-themes/tsconfig.node.json
@@ -0,0 +1,9 @@
+{
+  "compilerOptions": {
+    "composite": true,
+    "skipLibCheck": true,
+    "module": "ESNext",
+    "moduleResolution": "bundler"
+  },
+  "include": ["vite.config.ts"]
+}
diff --git a/svelte-code-block-themes/vite.config.ts b/svelte-code-block-themes/vite.config.ts
new file mode 100644
index 0000000000..11edea7f23
--- /dev/null
+++ b/svelte-code-block-themes/vite.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'vite'
+import { svelte } from '@sveltejs/vite-plugin-svelte'
+import tailwindcss from '@tailwindcss/vite'
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  plugins: [svelte(), tailwindcss()],
+})
diff --git a/svelte-code-block/.gitignore b/svelte-code-block/.gitignore
new file mode 100644
index 0000000000..5d6225c6df
--- /dev/null
+++ b/svelte-code-block/.gitignore
@@ -0,0 +1,4 @@
+node_modules
+dist
+.next
+.svelte-kit
diff --git a/svelte-code-block/README.md b/svelte-code-block/README.md
new file mode 100644
index 0000000000..0230ffd133
--- /dev/null
+++ b/svelte-code-block/README.md
@@ -0,0 +1,15 @@
+# svelte-code-block
+
+A [ProseKit](https://prosekit.dev) example.
+
+[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-code-block)
+[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-code-block)
+
+Run the example locally with:
+
+```bash
+npx degit prosekit/examples/svelte-code-block svelte-code-block
+cd svelte-code-block
+npm install
+npm run dev
+```
diff --git a/svelte-code-block/index.html b/svelte-code-block/index.html
new file mode 100644
index 0000000000..58212c2501
--- /dev/null
+++ b/svelte-code-block/index.html
@@ -0,0 +1,12 @@
+
+
+  
+    
+    
+    ProseKit + Svelte
+  
+  
+    
+ + + diff --git a/svelte-code-block/package.json b/svelte-code-block/package.json new file mode 100644 index 0000000000..c37e5df28e --- /dev/null +++ b/svelte-code-block/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-code-block", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-code-block/src/App.svelte b/svelte-code-block/src/App.svelte new file mode 100644 index 0000000000..c4e6b48f16 --- /dev/null +++ b/svelte-code-block/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-code-block/src/app.css b/svelte-code-block/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-code-block/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-code-block/src/components/editor/examples/code-block/editor.svelte b/svelte-code-block/src/components/editor/examples/code-block/editor.svelte new file mode 100644 index 0000000000..d983b9dd39 --- /dev/null +++ b/svelte-code-block/src/components/editor/examples/code-block/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-code-block/src/components/editor/examples/code-block/extension.ts b/svelte-code-block/src/components/editor/examples/code-block/extension.ts new file mode 100644 index 0000000000..099cacf03b --- /dev/null +++ b/svelte-code-block/src/components/editor/examples/code-block/extension.ts @@ -0,0 +1,24 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { + defineCodeBlock, + defineCodeBlockShiki, +} from 'prosekit/extensions/code-block' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCodeBlock(), + defineCodeBlockShiki(), + defineCodeBlockView(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-code-block/src/components/editor/examples/code-block/index.ts b/svelte-code-block/src/components/editor/examples/code-block/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-code-block/src/components/editor/examples/code-block/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-code-block/src/components/editor/sample/sample-doc-code-block.ts b/svelte-code-block/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/svelte-code-block/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/svelte-code-block/src/components/editor/ui/button/button.svelte b/svelte-code-block/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-code-block/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-code-block/src/components/editor/ui/button/index.ts b/svelte-code-block/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-code-block/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-code-block/src/components/editor/ui/code-block-view/code-block-view.svelte b/svelte-code-block/src/components/editor/ui/code-block-view/code-block-view.svelte new file mode 100644 index 0000000000..aaa4617fc1 --- /dev/null +++ b/svelte-code-block/src/components/editor/ui/code-block-view/code-block-view.svelte @@ -0,0 +1,40 @@ + + + +

diff --git a/svelte-code-block/src/components/editor/ui/code-block-view/index.ts b/svelte-code-block/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..eb54b2f6d9
--- /dev/null
+++ b/svelte-code-block/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSvelteNodeView,
+  type SvelteNodeViewComponent,
+} from 'prosekit/svelte'
+
+import CodeBlockView from './code-block-view.svelte'
+
+export function defineCodeBlockView(): Extension {
+  return defineSvelteNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView as SvelteNodeViewComponent,
+  })
+}
diff --git a/svelte-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
new file mode 100644
index 0000000000..c80af45721
--- /dev/null
+++ b/svelte-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
@@ -0,0 +1,121 @@
+
+
+
+  
+    
+  
+
+  
+      {#if !file}
+        
+        
+      {/if}
+
+      {#if !url}
+        
+        
+      {/if}
+
+      {#if url}
+        
+      {/if}
+
+      {#if file}
+        
+      {/if}
+    
+
diff --git a/svelte-code-block/src/components/editor/ui/image-upload-popover/index.ts b/svelte-code-block/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..e53e71c348
--- /dev/null
+++ b/svelte-code-block/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover.svelte'
diff --git a/svelte-code-block/src/components/editor/ui/toolbar/index.ts b/svelte-code-block/src/components/editor/ui/toolbar/index.ts
new file mode 100644
index 0000000000..7b55cca073
--- /dev/null
+++ b/svelte-code-block/src/components/editor/ui/toolbar/index.ts
@@ -0,0 +1 @@
+export { default as Toolbar } from './toolbar.svelte'
diff --git a/svelte-code-block/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-code-block/src/components/editor/ui/toolbar/toolbar.svelte
new file mode 100644
index 0000000000..49bbeff5aa
--- /dev/null
+++ b/svelte-code-block/src/components/editor/ui/toolbar/toolbar.svelte
@@ -0,0 +1,365 @@
+
+
+
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-code-block/src/main.ts b/svelte-code-block/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-code-block/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-code-block/src/vite-env.d.ts b/svelte-code-block/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-code-block/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-code-block/svelte.config.js b/svelte-code-block/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-code-block/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-code-block/tsconfig.json b/svelte-code-block/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-code-block/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-code-block/tsconfig.node.json b/svelte-code-block/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-code-block/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-code-block/vite.config.ts b/svelte-code-block/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-code-block/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-code/.gitignore b/svelte-code/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-code/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-code/README.md b/svelte-code/README.md new file mode 100644 index 0000000000..0817bfa3ca --- /dev/null +++ b/svelte-code/README.md @@ -0,0 +1,15 @@ +# svelte-code + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-code) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-code) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-code svelte-code +cd svelte-code +npm install +npm run dev +``` diff --git a/svelte-code/index.html b/svelte-code/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-code/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-code/package.json b/svelte-code/package.json new file mode 100644 index 0000000000..85b82ecb3d --- /dev/null +++ b/svelte-code/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-code", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-code/src/App.svelte b/svelte-code/src/App.svelte new file mode 100644 index 0000000000..e77af1e003 --- /dev/null +++ b/svelte-code/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-code/src/app.css b/svelte-code/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-code/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-code/src/components/editor/examples/code/editor.svelte b/svelte-code/src/components/editor/examples/code/editor.svelte new file mode 100644 index 0000000000..e47d53633d --- /dev/null +++ b/svelte-code/src/components/editor/examples/code/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-code/src/components/editor/examples/code/extension.ts b/svelte-code/src/components/editor/examples/code/extension.ts new file mode 100644 index 0000000000..e9e273216e --- /dev/null +++ b/svelte-code/src/components/editor/examples/code/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCode(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-code/src/components/editor/examples/code/index.ts b/svelte-code/src/components/editor/examples/code/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-code/src/components/editor/examples/code/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-code/src/components/editor/sample/sample-doc-code.ts b/svelte-code/src/components/editor/sample/sample-doc-code.ts new file mode 100644 index 0000000000..2fdbcee1f3 --- /dev/null +++ b/svelte-code/src/components/editor/sample/sample-doc-code.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'This is code', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/svelte-code/src/components/editor/ui/button/button.svelte b/svelte-code/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-code/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-code/src/components/editor/ui/button/index.ts b/svelte-code/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-code/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-code/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-code/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-code/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-code/src/components/editor/ui/image-upload-popover/index.ts b/svelte-code/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-code/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-code/src/components/editor/ui/toolbar/index.ts b/svelte-code/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-code/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-code/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-code/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-code/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-code/src/main.ts b/svelte-code/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-code/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-code/src/vite-env.d.ts b/svelte-code/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-code/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-code/svelte.config.js b/svelte-code/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-code/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-code/tsconfig.json b/svelte-code/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-code/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-code/tsconfig.node.json b/svelte-code/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-code/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-code/vite.config.ts b/svelte-code/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-code/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-drop-cursor/.gitignore b/svelte-drop-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-drop-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-drop-cursor/README.md b/svelte-drop-cursor/README.md new file mode 100644 index 0000000000..022678b9f8 --- /dev/null +++ b/svelte-drop-cursor/README.md @@ -0,0 +1,15 @@ +# svelte-drop-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-drop-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-drop-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-drop-cursor svelte-drop-cursor +cd svelte-drop-cursor +npm install +npm run dev +``` diff --git a/svelte-drop-cursor/index.html b/svelte-drop-cursor/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-drop-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-drop-cursor/package.json b/svelte-drop-cursor/package.json new file mode 100644 index 0000000000..087738bb00 --- /dev/null +++ b/svelte-drop-cursor/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-drop-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-drop-cursor/src/App.svelte b/svelte-drop-cursor/src/App.svelte new file mode 100644 index 0000000000..4c88b27ec9 --- /dev/null +++ b/svelte-drop-cursor/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-drop-cursor/src/app.css b/svelte-drop-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-drop-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/editor.svelte b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/editor.svelte new file mode 100644 index 0000000000..2de79d237f --- /dev/null +++ b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/editor.svelte @@ -0,0 +1,28 @@ + + + +
+
+
+
+
+
diff --git a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts new file mode 100644 index 0000000000..fd79a2c96c --- /dev/null +++ b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts @@ -0,0 +1,23 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineImage(), + defineDropCursor({ + color: false, + width: 4, + class: 'transition-all bg-blue-500', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-drop-cursor/src/components/editor/examples/drop-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/svelte-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts new file mode 100644 index 0000000000..22c6b93465 --- /dev/null +++ b/svelte-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts @@ -0,0 +1,40 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the images below to see the custom drop cursor.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/320x240/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/green/320x240/40', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blue/320x240/187', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/red/320x240/188', + }, + }, + ], +} diff --git a/svelte-drop-cursor/src/main.ts b/svelte-drop-cursor/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-drop-cursor/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-drop-cursor/src/vite-env.d.ts b/svelte-drop-cursor/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-drop-cursor/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-drop-cursor/svelte.config.js b/svelte-drop-cursor/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-drop-cursor/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-drop-cursor/tsconfig.json b/svelte-drop-cursor/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-drop-cursor/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-drop-cursor/tsconfig.node.json b/svelte-drop-cursor/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-drop-cursor/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-drop-cursor/vite.config.ts b/svelte-drop-cursor/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-drop-cursor/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-emoji-rules/.gitignore b/svelte-emoji-rules/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-emoji-rules/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-emoji-rules/README.md b/svelte-emoji-rules/README.md new file mode 100644 index 0000000000..a634bfb847 --- /dev/null +++ b/svelte-emoji-rules/README.md @@ -0,0 +1,15 @@ +# svelte-emoji-rules + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-emoji-rules) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-emoji-rules) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-emoji-rules svelte-emoji-rules +cd svelte-emoji-rules +npm install +npm run dev +``` diff --git a/svelte-emoji-rules/index.html b/svelte-emoji-rules/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-emoji-rules/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-emoji-rules/package.json b/svelte-emoji-rules/package.json new file mode 100644 index 0000000000..e1a5d6e854 --- /dev/null +++ b/svelte-emoji-rules/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-emoji-rules", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-emoji-rules/src/App.svelte b/svelte-emoji-rules/src/App.svelte new file mode 100644 index 0000000000..7d5cc766ba --- /dev/null +++ b/svelte-emoji-rules/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-emoji-rules/src/app.css b/svelte-emoji-rules/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-emoji-rules/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/editor.svelte b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/editor.svelte new file mode 100644 index 0000000000..03b6c9f2ca --- /dev/null +++ b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/editor.svelte @@ -0,0 +1,20 @@ + + + +
+
+
+
+
+
diff --git a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts new file mode 100644 index 0000000000..5cac9cbc79 --- /dev/null +++ b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts @@ -0,0 +1,15 @@ +import { defineEnterRule } from 'prosekit/extensions/enter-rule' + +/** + * Converts the text before the text cursor into an emoji when pressing `Enter`. + */ +export function defineEmojiEnterRule() { + return defineEnterRule({ + regex: /:(apple|banana):$/, + handler: ({ match, from, to, state }) => { + const text = match[1] as 'apple' | 'banana' + const emoji = text === 'apple' ? '🍎' : '🍌' + return state.tr.replaceWith(from, to, state.schema.text(emoji)) + }, + }) +} diff --git a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts new file mode 100644 index 0000000000..bc9bcb8412 --- /dev/null +++ b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts @@ -0,0 +1,15 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { defineEmojiEnterRule } from './emoji' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineEmojiEnterRule(), + definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-emoji-rules/src/components/editor/examples/emoji-rules/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-emoji-rules/src/main.ts b/svelte-emoji-rules/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-emoji-rules/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-emoji-rules/src/vite-env.d.ts b/svelte-emoji-rules/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-emoji-rules/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-emoji-rules/svelte.config.js b/svelte-emoji-rules/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-emoji-rules/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-emoji-rules/tsconfig.json b/svelte-emoji-rules/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-emoji-rules/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-emoji-rules/tsconfig.node.json b/svelte-emoji-rules/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-emoji-rules/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-emoji-rules/vite.config.ts b/svelte-emoji-rules/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-emoji-rules/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-full/.gitignore b/svelte-full/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-full/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-full/README.md b/svelte-full/README.md new file mode 100644 index 0000000000..fb6da41106 --- /dev/null +++ b/svelte-full/README.md @@ -0,0 +1,15 @@ +# svelte-full + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-full) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-full) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-full svelte-full +cd svelte-full +npm install +npm run dev +``` diff --git a/svelte-full/index.html b/svelte-full/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-full/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-full/package.json b/svelte-full/package.json new file mode 100644 index 0000000000..f2a3bd21be --- /dev/null +++ b/svelte-full/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-svelte-full", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-full/src/App.svelte b/svelte-full/src/App.svelte new file mode 100644 index 0000000000..55103feeed --- /dev/null +++ b/svelte-full/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-full/src/app.css b/svelte-full/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-full/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-full/src/components/editor/examples/full/editor.svelte b/svelte-full/src/components/editor/examples/full/editor.svelte new file mode 100644 index 0000000000..09f3d7d9d3 --- /dev/null +++ b/svelte-full/src/components/editor/examples/full/editor.svelte @@ -0,0 +1,47 @@ + + + +
+ +
+
+ + + + + + + +
+
+
diff --git a/svelte-full/src/components/editor/examples/full/extension.ts b/svelte-full/src/components/editor/examples/full/extension.ts new file mode 100644 index 0000000000..5fc2f60685 --- /dev/null +++ b/svelte-full/src/components/editor/examples/full/extension.ts @@ -0,0 +1,34 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineImageUploadHandler } from 'prosekit/extensions/image' +import { defineMath } from 'prosekit/extensions/math' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' +import { sampleUploader } from '../../sample/sample-uploader' +import { defineCodeBlockView } from '../../ui/code-block-view' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + defineMention(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + defineCodeBlockShiki(), + defineHorizontalRule(), + defineCodeBlockView(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-full/src/components/editor/examples/full/index.ts b/svelte-full/src/components/editor/examples/full/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-full/src/components/editor/examples/full/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-full/src/components/editor/sample/katex.ts b/svelte-full/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/svelte-full/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/svelte-full/src/components/editor/sample/sample-doc-full.ts b/svelte-full/src/components/editor/sample/sample-doc-full.ts new file mode 100644 index 0000000000..13e49b634d --- /dev/null +++ b/svelte-full/src/components/editor/sample/sample-doc-full.ts @@ -0,0 +1,442 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'The editor that thinks like you' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', + }, + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'writing without barriers', + }, + { type: 'text', text: '.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Text that shines.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Make your words ' }, + { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, + { type: 'text', text: ', or ' }, + { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, + { type: 'text', text: '. Add ' }, + { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, + { type: 'text', text: ' that stands out. Create ' }, + { + type: 'text', + marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], + text: 'links', + }, + { type: 'text', text: ' that connect.' }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Select any text to format it. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '@' }, + { type: 'text', text: ' to mention ' }, + { + type: 'mention', + attrs: { id: '39', value: '@someone', kind: 'user' }, + }, + { type: 'text', text: ' or ' }, + { type: 'text', marks: [{ type: 'code' }], text: '#' }, + { type: 'text', text: ' for ' }, + { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, + { type: 'text', text: '. Press ' }, + { type: 'text', marks: [{ type: 'code' }], text: '/' }, + { type: 'text', text: " and discover what's possible." }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Lists that organize.' }], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Bullet points that guide thoughts' }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Nested lists for complex ideas' }], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sub-points flow naturally' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Tasks that focus' }], + }, + { + type: 'list', + attrs: { kind: 'task', order: null, checked: true, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Done feels good' }], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Todo drives action' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Numbered steps' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sequential thinking' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Clear progress' }], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Code that inspires.' }], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Images that captivate.' }], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/season/320x240/107', + }, + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the handle in the bottom right corner to resize.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Tables that structure.' }], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'Feature', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'How to use', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Format text' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Select and choose' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Perfect styling' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Add mentions' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Type @ and name' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Connected ideas' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Insert anything' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Press / for menu' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Endless possibilities' }], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Math that renders.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Inline math like ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' appears within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Quotes that inspire.' }], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: '"This is not just an editor. This is how writing should feel."', + }, + ], + }, + ], + }, + { type: 'horizontalRule' }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Start typing. Everything else just flows.' }, + ], + }, + ], +} diff --git a/svelte-full/src/components/editor/sample/sample-tag-data.ts b/svelte-full/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/svelte-full/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/svelte-full/src/components/editor/sample/sample-uploader.ts b/svelte-full/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/svelte-full/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/svelte-full/src/components/editor/sample/sample-user-data.ts b/svelte-full/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/svelte-full/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/svelte-full/src/components/editor/ui/block-handle/block-handle.svelte b/svelte-full/src/components/editor/ui/block-handle/block-handle.svelte new file mode 100644 index 0000000000..f67e42dc91 --- /dev/null +++ b/svelte-full/src/components/editor/ui/block-handle/block-handle.svelte @@ -0,0 +1,28 @@ + + + + + + +
+
+ +
+
+
+
+
diff --git a/svelte-full/src/components/editor/ui/block-handle/index.ts b/svelte-full/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..6d21191384 --- /dev/null +++ b/svelte-full/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.svelte' diff --git a/svelte-full/src/components/editor/ui/button/button.svelte b/svelte-full/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-full/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-full/src/components/editor/ui/button/index.ts b/svelte-full/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-full/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-full/src/components/editor/ui/code-block-view/code-block-view.svelte b/svelte-full/src/components/editor/ui/code-block-view/code-block-view.svelte new file mode 100644 index 0000000000..aaa4617fc1 --- /dev/null +++ b/svelte-full/src/components/editor/ui/code-block-view/code-block-view.svelte @@ -0,0 +1,40 @@ + + + +

diff --git a/svelte-full/src/components/editor/ui/code-block-view/index.ts b/svelte-full/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..eb54b2f6d9
--- /dev/null
+++ b/svelte-full/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSvelteNodeView,
+  type SvelteNodeViewComponent,
+} from 'prosekit/svelte'
+
+import CodeBlockView from './code-block-view.svelte'
+
+export function defineCodeBlockView(): Extension {
+  return defineSvelteNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView as SvelteNodeViewComponent,
+  })
+}
diff --git a/svelte-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/svelte-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte
new file mode 100644
index 0000000000..7f6cac1db0
--- /dev/null
+++ b/svelte-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte
@@ -0,0 +1,5 @@
+
+
+
diff --git a/svelte-full/src/components/editor/ui/drop-indicator/index.ts b/svelte-full/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..06e89357ed
--- /dev/null
+++ b/svelte-full/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator.svelte'
diff --git a/svelte-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
new file mode 100644
index 0000000000..c80af45721
--- /dev/null
+++ b/svelte-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
@@ -0,0 +1,121 @@
+
+
+
+  
+    
+  
+
+  
+      {#if !file}
+        
+        
+      {/if}
+
+      {#if !url}
+        
+        
+      {/if}
+
+      {#if url}
+        
+      {/if}
+
+      {#if file}
+        
+      {/if}
+    
+
diff --git a/svelte-full/src/components/editor/ui/image-upload-popover/index.ts b/svelte-full/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..e53e71c348
--- /dev/null
+++ b/svelte-full/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover.svelte'
diff --git a/svelte-full/src/components/editor/ui/image-view/image-view.svelte b/svelte-full/src/components/editor/ui/image-view/image-view.svelte
new file mode 100644
index 0000000000..b8f0fd3971
--- /dev/null
+++ b/svelte-full/src/components/editor/ui/image-view/image-view.svelte
@@ -0,0 +1,97 @@
+
+
+ props.setAttrs(event.detail)}
+>
+  {#if url && !error}
+    upload preview
+  {/if}
+  {#if uploading && !error}
+    
+
+
{Math.round(progress * 100)}%
+
+ {/if} + {#if error} +
+
+ +
+ {/if} + +
+
+
diff --git a/svelte-full/src/components/editor/ui/image-view/index.ts b/svelte-full/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..d39bdb81e8 --- /dev/null +++ b/svelte-full/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + defineSvelteNodeView, + type SvelteNodeViewComponent, +} from 'prosekit/svelte' + +import ImageView from './image-view.svelte' + +export function defineImageView(): Extension { + return defineSvelteNodeView({ + name: 'image', + component: ImageView as SvelteNodeViewComponent, + }) +} diff --git a/svelte-full/src/components/editor/ui/inline-menu/index.ts b/svelte-full/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..bf78dd2139 --- /dev/null +++ b/svelte-full/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-full/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-full/src/components/editor/ui/inline-menu/inline-menu.svelte new file mode 100644 index 0000000000..989f0c013b --- /dev/null +++ b/svelte-full/src/components/editor/ui/inline-menu/inline-menu.svelte @@ -0,0 +1,207 @@ + + + { + if (!event.detail) linkMenuOpen = false + }} +> + + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.link?.canExec && $items.link} + + {/if} + + + + + { + linkMenuOpen = event.detail + }} +> + + + {#if linkMenuOpen && $items.link} +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ {/if} + {#if $items.link?.isActive} + + {/if} +
+
+
diff --git a/svelte-full/src/components/editor/ui/slash-menu/index.ts b/svelte-full/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..856d4e6b43 --- /dev/null +++ b/svelte-full/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu.svelte' diff --git a/svelte-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte b/svelte-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte new file mode 100644 index 0000000000..37cea8de67 --- /dev/null +++ b/svelte-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte @@ -0,0 +1,7 @@ + + + + No results + diff --git a/svelte-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte b/svelte-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte new file mode 100644 index 0000000000..52126eeb68 --- /dev/null +++ b/svelte-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte @@ -0,0 +1,15 @@ + + + + {props.label}{#if props.kbd}{props.kbd}{/if} + diff --git a/svelte-full/src/components/editor/ui/slash-menu/slash-menu.svelte b/svelte-full/src/components/editor/ui/slash-menu/slash-menu.svelte new file mode 100644 index 0000000000..5da516b44f --- /dev/null +++ b/svelte-full/src/components/editor/ui/slash-menu/slash-menu.svelte @@ -0,0 +1,94 @@ + + + + + +
+ $editor.commands.setParagraph()} + /> + + $editor.commands.setHeading({ level: 1 })} + /> + + $editor.commands.setHeading({ level: 2 })} + /> + + $editor.commands.setHeading({ level: 3 })} + /> + + $editor.commands.wrapInList({ kind: 'bullet' })} + /> + + $editor.commands.wrapInList({ kind: 'ordered' })} + /> + + $editor.commands.wrapInList({ kind: 'task' })} + /> + + $editor.commands.wrapInList({ kind: 'toggle' })} + /> + + $editor.commands.setBlockquote()} + /> + + $editor.commands.insertTable({ row: 3, col: 3 })} + /> + + $editor.commands.insertHorizontalRule()} + /> + + $editor.commands.setCodeBlock()} + /> + + +
+
+
+
diff --git a/svelte-full/src/components/editor/ui/table-handle/index.ts b/svelte-full/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..308cef59de --- /dev/null +++ b/svelte-full/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle.svelte' diff --git a/svelte-full/src/components/editor/ui/table-handle/table-handle.svelte b/svelte-full/src/components/editor/ui/table-handle/table-handle.svelte new file mode 100644 index 0000000000..fc91f9a438 --- /dev/null +++ b/svelte-full/src/components/editor/ui/table-handle/table-handle.svelte @@ -0,0 +1,182 @@ + + + + + + + + + +
+
+ + + {#if $state.addTableColumnBefore.canExec} + + Insert Left + + {/if} + {#if $state.addTableColumnAfter.canExec} + + Insert Right + + {/if} + {#if $state.deleteCellSelection.canExec} + + Clear Contents + Del + + {/if} + {#if $state.deleteTableColumn.canExec} + + Delete Column + + {/if} + {#if $state.deleteTable.canExec} + + Delete Table + + {/if} + + +
+
+
+ + + + +
+
+ + + {#if $state.addTableRowAbove.canExec} + + Insert Above + + {/if} + {#if $state.addTableRowBelow.canExec} + + Insert Below + + {/if} + {#if $state.deleteCellSelection.canExec} + + Clear Contents + Del + + {/if} + {#if $state.deleteTableRow.canExec} + + Delete Row + + {/if} + {#if $state.deleteTable.canExec} + + Delete Table + + {/if} + + +
+
+
+
diff --git a/svelte-full/src/components/editor/ui/tag-menu/index.ts b/svelte-full/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..0884d7f5a1 --- /dev/null +++ b/svelte-full/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu.svelte' diff --git a/svelte-full/src/components/editor/ui/tag-menu/tag-menu.svelte b/svelte-full/src/components/editor/ui/tag-menu/tag-menu.svelte new file mode 100644 index 0000000000..8b9bf23f30 --- /dev/null +++ b/svelte-full/src/components/editor/ui/tag-menu/tag-menu.svelte @@ -0,0 +1,53 @@ + + + + + +
+ + No results + + + {#each props.tags as tag (tag.id)} + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + {/each} +
+
+
+
diff --git a/svelte-full/src/components/editor/ui/toolbar/index.ts b/svelte-full/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-full/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-full/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-full/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-full/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-full/src/components/editor/ui/user-menu/index.ts b/svelte-full/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..7dbbd80d0e --- /dev/null +++ b/svelte-full/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu.svelte' diff --git a/svelte-full/src/components/editor/ui/user-menu/user-menu.svelte b/svelte-full/src/components/editor/ui/user-menu/user-menu.svelte new file mode 100644 index 0000000000..5c0475d87e --- /dev/null +++ b/svelte-full/src/components/editor/ui/user-menu/user-menu.svelte @@ -0,0 +1,70 @@ + + + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} +> + + +
+ + {loading ? 'Loading...' : 'No results'} + + + {#each props.users as user (user.id)} + handleUserInsert(user.id, user.name)} + > + {#if loading} + + {user.name} + + {:else} + + {user.name} + + {/if} + + {/each} +
+
+
+
diff --git a/svelte-full/src/main.ts b/svelte-full/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-full/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-full/src/vite-env.d.ts b/svelte-full/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-full/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-full/svelte.config.js b/svelte-full/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-full/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-full/tsconfig.json b/svelte-full/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-full/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-full/tsconfig.node.json b/svelte-full/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-full/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-full/vite.config.ts b/svelte-full/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-full/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-gap-cursor/.gitignore b/svelte-gap-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-gap-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-gap-cursor/README.md b/svelte-gap-cursor/README.md new file mode 100644 index 0000000000..da5cd4ead9 --- /dev/null +++ b/svelte-gap-cursor/README.md @@ -0,0 +1,15 @@ +# svelte-gap-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-gap-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-gap-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-gap-cursor svelte-gap-cursor +cd svelte-gap-cursor +npm install +npm run dev +``` diff --git a/svelte-gap-cursor/index.html b/svelte-gap-cursor/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-gap-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-gap-cursor/package.json b/svelte-gap-cursor/package.json new file mode 100644 index 0000000000..b96f7026b0 --- /dev/null +++ b/svelte-gap-cursor/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-gap-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-gap-cursor/src/App.svelte b/svelte-gap-cursor/src/App.svelte new file mode 100644 index 0000000000..7380fa3b5d --- /dev/null +++ b/svelte-gap-cursor/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-gap-cursor/src/app.css b/svelte-gap-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-gap-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/editor.svelte b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/editor.svelte new file mode 100644 index 0000000000..00c2148aa1 --- /dev/null +++ b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/editor.svelte @@ -0,0 +1,28 @@ + + + +
+
+
+
+
+
diff --git a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts new file mode 100644 index 0000000000..599497170d --- /dev/null +++ b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts @@ -0,0 +1,19 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineGapCursor(), + defineImage(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-gap-cursor/src/components/editor/examples/gap-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/svelte-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts new file mode 100644 index 0000000000..e40ee2a83b --- /dev/null +++ b/svelte-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts @@ -0,0 +1,28 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + ], +} diff --git a/svelte-gap-cursor/src/main.ts b/svelte-gap-cursor/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-gap-cursor/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-gap-cursor/src/vite-env.d.ts b/svelte-gap-cursor/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-gap-cursor/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-gap-cursor/svelte.config.js b/svelte-gap-cursor/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-gap-cursor/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-gap-cursor/tsconfig.json b/svelte-gap-cursor/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-gap-cursor/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-gap-cursor/tsconfig.node.json b/svelte-gap-cursor/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-gap-cursor/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-gap-cursor/vite.config.ts b/svelte-gap-cursor/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-gap-cursor/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-hard-break/.gitignore b/svelte-hard-break/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-hard-break/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-hard-break/README.md b/svelte-hard-break/README.md new file mode 100644 index 0000000000..702c6a5208 --- /dev/null +++ b/svelte-hard-break/README.md @@ -0,0 +1,15 @@ +# svelte-hard-break + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-hard-break) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-hard-break) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-hard-break svelte-hard-break +cd svelte-hard-break +npm install +npm run dev +``` diff --git a/svelte-hard-break/index.html b/svelte-hard-break/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-hard-break/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-hard-break/package.json b/svelte-hard-break/package.json new file mode 100644 index 0000000000..80611d0502 --- /dev/null +++ b/svelte-hard-break/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-hard-break", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-hard-break/src/App.svelte b/svelte-hard-break/src/App.svelte new file mode 100644 index 0000000000..fa30b62cc3 --- /dev/null +++ b/svelte-hard-break/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-hard-break/src/app.css b/svelte-hard-break/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-hard-break/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-hard-break/src/components/editor/examples/hard-break/editor.svelte b/svelte-hard-break/src/components/editor/examples/hard-break/editor.svelte new file mode 100644 index 0000000000..c431ae655a --- /dev/null +++ b/svelte-hard-break/src/components/editor/examples/hard-break/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-hard-break/src/components/editor/examples/hard-break/extension.ts b/svelte-hard-break/src/components/editor/examples/hard-break/extension.ts new file mode 100644 index 0000000000..cad2881056 --- /dev/null +++ b/svelte-hard-break/src/components/editor/examples/hard-break/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHardBreak } from 'prosekit/extensions/hard-break' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHardBreak(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-hard-break/src/components/editor/examples/hard-break/index.ts b/svelte-hard-break/src/components/editor/examples/hard-break/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-hard-break/src/components/editor/examples/hard-break/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-hard-break/src/components/editor/examples/hard-break/toolbar.svelte b/svelte-hard-break/src/components/editor/examples/hard-break/toolbar.svelte new file mode 100644 index 0000000000..d558b234ea --- /dev/null +++ b/svelte-hard-break/src/components/editor/examples/hard-break/toolbar.svelte @@ -0,0 +1,29 @@ + + +
+ +
diff --git a/svelte-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/svelte-hard-break/src/components/editor/sample/sample-doc-hard-break.ts new file mode 100644 index 0000000000..e1c9786b72 --- /dev/null +++ b/svelte-hard-break/src/components/editor/sample/sample-doc-hard-break.ts @@ -0,0 +1,68 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: "O'er all the hilltops", + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Is quiet now,', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'In all the treetops', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hearest thou', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hardly a breath;', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'The birds are asleep in the trees:', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Wait, soon like these', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Thou too shalt rest.', + }, + { + type: 'hardBreak', + }, + ], + }, + ], +} diff --git a/svelte-hard-break/src/components/editor/ui/button/button.svelte b/svelte-hard-break/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-hard-break/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-hard-break/src/components/editor/ui/button/index.ts b/svelte-hard-break/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-hard-break/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-hard-break/src/main.ts b/svelte-hard-break/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-hard-break/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-hard-break/src/vite-env.d.ts b/svelte-hard-break/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-hard-break/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-hard-break/svelte.config.js b/svelte-hard-break/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-hard-break/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-hard-break/tsconfig.json b/svelte-hard-break/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-hard-break/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-hard-break/tsconfig.node.json b/svelte-hard-break/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-hard-break/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-hard-break/vite.config.ts b/svelte-hard-break/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-hard-break/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-heading/.gitignore b/svelte-heading/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-heading/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-heading/README.md b/svelte-heading/README.md new file mode 100644 index 0000000000..56b4c5ec1f --- /dev/null +++ b/svelte-heading/README.md @@ -0,0 +1,15 @@ +# svelte-heading + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-heading) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-heading) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-heading svelte-heading +cd svelte-heading +npm install +npm run dev +``` diff --git a/svelte-heading/index.html b/svelte-heading/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-heading/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-heading/package.json b/svelte-heading/package.json new file mode 100644 index 0000000000..cd1f9cef1b --- /dev/null +++ b/svelte-heading/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-heading", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-heading/src/App.svelte b/svelte-heading/src/App.svelte new file mode 100644 index 0000000000..20ae91e9ec --- /dev/null +++ b/svelte-heading/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-heading/src/app.css b/svelte-heading/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-heading/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-heading/src/components/editor/examples/heading/editor.svelte b/svelte-heading/src/components/editor/examples/heading/editor.svelte new file mode 100644 index 0000000000..3933196cd5 --- /dev/null +++ b/svelte-heading/src/components/editor/examples/heading/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-heading/src/components/editor/examples/heading/extension.ts b/svelte-heading/src/components/editor/examples/heading/extension.ts new file mode 100644 index 0000000000..e4f8e6ace0 --- /dev/null +++ b/svelte-heading/src/components/editor/examples/heading/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHeading(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-heading/src/components/editor/examples/heading/index.ts b/svelte-heading/src/components/editor/examples/heading/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-heading/src/components/editor/examples/heading/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-heading/src/components/editor/sample/sample-doc-heading.ts b/svelte-heading/src/components/editor/sample/sample-doc-heading.ts new file mode 100644 index 0000000000..210497e633 --- /dev/null +++ b/svelte-heading/src/components/editor/sample/sample-doc-heading.ts @@ -0,0 +1,23 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'H1' }], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'H2' }], + }, + { + type: 'heading', + attrs: { level: 3 }, + content: [{ type: 'text', text: 'H3' }], + }, + { type: 'paragraph', content: [] }, + ], +} diff --git a/svelte-heading/src/components/editor/ui/button/button.svelte b/svelte-heading/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-heading/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-heading/src/components/editor/ui/button/index.ts b/svelte-heading/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-heading/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-heading/src/components/editor/ui/image-upload-popover/index.ts b/svelte-heading/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-heading/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-heading/src/components/editor/ui/toolbar/index.ts b/svelte-heading/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-heading/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-heading/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-heading/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-heading/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-heading/src/main.ts b/svelte-heading/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-heading/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-heading/src/vite-env.d.ts b/svelte-heading/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-heading/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-heading/svelte.config.js b/svelte-heading/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-heading/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-heading/tsconfig.json b/svelte-heading/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-heading/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-heading/tsconfig.node.json b/svelte-heading/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-heading/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-heading/vite.config.ts b/svelte-heading/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-heading/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-highlight/.gitignore b/svelte-highlight/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-highlight/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-highlight/README.md b/svelte-highlight/README.md new file mode 100644 index 0000000000..879f073aa2 --- /dev/null +++ b/svelte-highlight/README.md @@ -0,0 +1,15 @@ +# svelte-highlight + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-highlight) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-highlight) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-highlight svelte-highlight +cd svelte-highlight +npm install +npm run dev +``` diff --git a/svelte-highlight/index.html b/svelte-highlight/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-highlight/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-highlight/package.json b/svelte-highlight/package.json new file mode 100644 index 0000000000..d5d0161644 --- /dev/null +++ b/svelte-highlight/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-highlight", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-highlight/src/App.svelte b/svelte-highlight/src/App.svelte new file mode 100644 index 0000000000..1183340f4a --- /dev/null +++ b/svelte-highlight/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-highlight/src/app.css b/svelte-highlight/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-highlight/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-highlight/src/components/editor/examples/highlight/editor.svelte b/svelte-highlight/src/components/editor/examples/highlight/editor.svelte new file mode 100644 index 0000000000..90d6bcada7 --- /dev/null +++ b/svelte-highlight/src/components/editor/examples/highlight/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-highlight/src/components/editor/examples/highlight/extension.ts b/svelte-highlight/src/components/editor/examples/highlight/extension.ts new file mode 100644 index 0000000000..abc131c3be --- /dev/null +++ b/svelte-highlight/src/components/editor/examples/highlight/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHighlight } from 'prosekit/extensions/highlight' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHighlight(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-highlight/src/components/editor/examples/highlight/index.ts b/svelte-highlight/src/components/editor/examples/highlight/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-highlight/src/components/editor/examples/highlight/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-highlight/src/components/editor/examples/highlight/toolbar.svelte b/svelte-highlight/src/components/editor/examples/highlight/toolbar.svelte new file mode 100644 index 0000000000..5c1e9f3896 --- /dev/null +++ b/svelte-highlight/src/components/editor/examples/highlight/toolbar.svelte @@ -0,0 +1,30 @@ + + +
+ +
diff --git a/svelte-highlight/src/components/editor/sample/sample-doc-highlight.ts b/svelte-highlight/src/components/editor/sample/sample-doc-highlight.ts new file mode 100644 index 0000000000..0de1a1f7b2 --- /dev/null +++ b/svelte-highlight/src/components/editor/sample/sample-doc-highlight.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'highlight', + }, + ], + text: 'This is highlighted text', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/svelte-highlight/src/components/editor/ui/button/button.svelte b/svelte-highlight/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-highlight/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-highlight/src/components/editor/ui/button/index.ts b/svelte-highlight/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-highlight/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-highlight/src/main.ts b/svelte-highlight/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-highlight/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-highlight/src/vite-env.d.ts b/svelte-highlight/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-highlight/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-highlight/svelte.config.js b/svelte-highlight/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-highlight/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-highlight/tsconfig.json b/svelte-highlight/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-highlight/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-highlight/tsconfig.node.json b/svelte-highlight/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-highlight/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-highlight/vite.config.ts b/svelte-highlight/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-highlight/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-horizontal-rule/.gitignore b/svelte-horizontal-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-horizontal-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-horizontal-rule/README.md b/svelte-horizontal-rule/README.md new file mode 100644 index 0000000000..555c4c7853 --- /dev/null +++ b/svelte-horizontal-rule/README.md @@ -0,0 +1,15 @@ +# svelte-horizontal-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-horizontal-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-horizontal-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-horizontal-rule svelte-horizontal-rule +cd svelte-horizontal-rule +npm install +npm run dev +``` diff --git a/svelte-horizontal-rule/index.html b/svelte-horizontal-rule/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-horizontal-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-horizontal-rule/package.json b/svelte-horizontal-rule/package.json new file mode 100644 index 0000000000..45acb8f3cd --- /dev/null +++ b/svelte-horizontal-rule/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-horizontal-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-horizontal-rule/src/App.svelte b/svelte-horizontal-rule/src/App.svelte new file mode 100644 index 0000000000..36fa28d72c --- /dev/null +++ b/svelte-horizontal-rule/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-horizontal-rule/src/app.css b/svelte-horizontal-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-horizontal-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.svelte b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.svelte new file mode 100644 index 0000000000..741b836c3c --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.svelte @@ -0,0 +1,23 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts new file mode 100644 index 0000000000..49b6121eeb --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHorizontalRule(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-horizontal-rule/src/components/editor/ui/button/button.svelte b/svelte-horizontal-rule/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-horizontal-rule/src/components/editor/ui/button/index.ts b/svelte-horizontal-rule/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/svelte-horizontal-rule/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-horizontal-rule/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-horizontal-rule/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-horizontal-rule/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-horizontal-rule/src/main.ts b/svelte-horizontal-rule/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-horizontal-rule/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-horizontal-rule/src/vite-env.d.ts b/svelte-horizontal-rule/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-horizontal-rule/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-horizontal-rule/svelte.config.js b/svelte-horizontal-rule/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-horizontal-rule/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-horizontal-rule/tsconfig.json b/svelte-horizontal-rule/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-horizontal-rule/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-horizontal-rule/tsconfig.node.json b/svelte-horizontal-rule/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-horizontal-rule/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-horizontal-rule/vite.config.ts b/svelte-horizontal-rule/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-horizontal-rule/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-image-view/.gitignore b/svelte-image-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-image-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-image-view/README.md b/svelte-image-view/README.md new file mode 100644 index 0000000000..a69dc143f0 --- /dev/null +++ b/svelte-image-view/README.md @@ -0,0 +1,15 @@ +# svelte-image-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-image-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-image-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-image-view svelte-image-view +cd svelte-image-view +npm install +npm run dev +``` diff --git a/svelte-image-view/index.html b/svelte-image-view/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-image-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-image-view/package.json b/svelte-image-view/package.json new file mode 100644 index 0000000000..fb8dd1c8c8 --- /dev/null +++ b/svelte-image-view/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-image-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-image-view/src/App.svelte b/svelte-image-view/src/App.svelte new file mode 100644 index 0000000000..3417c3812d --- /dev/null +++ b/svelte-image-view/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-image-view/src/app.css b/svelte-image-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-image-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-image-view/src/components/editor/examples/image-view/editor.svelte b/svelte-image-view/src/components/editor/examples/image-view/editor.svelte new file mode 100644 index 0000000000..6386d5867a --- /dev/null +++ b/svelte-image-view/src/components/editor/examples/image-view/editor.svelte @@ -0,0 +1,28 @@ + + + +
+
+
+
+
+
diff --git a/svelte-image-view/src/components/editor/examples/image-view/extension.ts b/svelte-image-view/src/components/editor/examples/image-view/extension.ts new file mode 100644 index 0000000000..a21febf634 --- /dev/null +++ b/svelte-image-view/src/components/editor/examples/image-view/extension.ts @@ -0,0 +1,18 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineImageUploadHandler } from 'prosekit/extensions/image' + +import { sampleUploader } from '../../sample/sample-uploader' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-image-view/src/components/editor/examples/image-view/index.ts b/svelte-image-view/src/components/editor/examples/image-view/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-image-view/src/components/editor/examples/image-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-image-view/src/components/editor/sample/sample-doc-image.ts b/svelte-image-view/src/components/editor/sample/sample-doc-image.ts new file mode 100644 index 0000000000..c97628339d --- /dev/null +++ b/svelte-image-view/src/components/editor/sample/sample-doc-image.ts @@ -0,0 +1,32 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Paste or drop an image to upload it.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/white/200x200/1', + width: 160, + height: 160, + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/640x360/42', + width: 240, + height: 135, + }, + }, + ], +} diff --git a/svelte-image-view/src/components/editor/sample/sample-uploader.ts b/svelte-image-view/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/svelte-image-view/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/svelte-image-view/src/components/editor/ui/image-view/image-view.svelte b/svelte-image-view/src/components/editor/ui/image-view/image-view.svelte new file mode 100644 index 0000000000..b8f0fd3971 --- /dev/null +++ b/svelte-image-view/src/components/editor/ui/image-view/image-view.svelte @@ -0,0 +1,97 @@ + + + props.setAttrs(event.detail)} +> + {#if url && !error} + upload preview + {/if} + {#if uploading && !error} +
+
+
{Math.round(progress * 100)}%
+
+ {/if} + {#if error} +
+
+ +
+ {/if} + +
+
+
diff --git a/svelte-image-view/src/components/editor/ui/image-view/index.ts b/svelte-image-view/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..d39bdb81e8 --- /dev/null +++ b/svelte-image-view/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + defineSvelteNodeView, + type SvelteNodeViewComponent, +} from 'prosekit/svelte' + +import ImageView from './image-view.svelte' + +export function defineImageView(): Extension { + return defineSvelteNodeView({ + name: 'image', + component: ImageView as SvelteNodeViewComponent, + }) +} diff --git a/svelte-image-view/src/main.ts b/svelte-image-view/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-image-view/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-image-view/src/vite-env.d.ts b/svelte-image-view/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-image-view/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-image-view/svelte.config.js b/svelte-image-view/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-image-view/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-image-view/tsconfig.json b/svelte-image-view/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-image-view/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-image-view/tsconfig.node.json b/svelte-image-view/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-image-view/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-image-view/vite.config.ts b/svelte-image-view/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-image-view/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-inline-menu/.gitignore b/svelte-inline-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-inline-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-inline-menu/README.md b/svelte-inline-menu/README.md new file mode 100644 index 0000000000..46d48f5663 --- /dev/null +++ b/svelte-inline-menu/README.md @@ -0,0 +1,15 @@ +# svelte-inline-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-inline-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-inline-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-inline-menu svelte-inline-menu +cd svelte-inline-menu +npm install +npm run dev +``` diff --git a/svelte-inline-menu/index.html b/svelte-inline-menu/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-inline-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-inline-menu/package.json b/svelte-inline-menu/package.json new file mode 100644 index 0000000000..709502a18d --- /dev/null +++ b/svelte-inline-menu/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-inline-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-inline-menu/src/App.svelte b/svelte-inline-menu/src/App.svelte new file mode 100644 index 0000000000..0a90100c19 --- /dev/null +++ b/svelte-inline-menu/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-inline-menu/src/app.css b/svelte-inline-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-inline-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-inline-menu/src/components/editor/examples/inline-menu/editor.svelte b/svelte-inline-menu/src/components/editor/examples/inline-menu/editor.svelte new file mode 100644 index 0000000000..1c85d78255 --- /dev/null +++ b/svelte-inline-menu/src/components/editor/examples/inline-menu/editor.svelte @@ -0,0 +1,30 @@ + + + +
+
+
+ +
+
+
diff --git a/svelte-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/svelte-inline-menu/src/components/editor/examples/inline-menu/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/svelte-inline-menu/src/components/editor/examples/inline-menu/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/svelte-inline-menu/src/components/editor/examples/inline-menu/index.ts b/svelte-inline-menu/src/components/editor/examples/inline-menu/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-inline-menu/src/components/editor/examples/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/svelte-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts new file mode 100644 index 0000000000..62a5984cb0 --- /dev/null +++ b/svelte-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts @@ -0,0 +1,33 @@ +import type { NodeJSON } from 'prosekit/core' + +const loremText = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'Try to select some text', + }, + ], + }, + ...Array.from({ length: 10 }, () => ({ + type: 'paragraph' as const, + content: [ + { + type: 'text' as const, + text: loremText, + }, + ], + })), + ], +} diff --git a/svelte-inline-menu/src/components/editor/ui/button/button.svelte b/svelte-inline-menu/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-inline-menu/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-inline-menu/src/components/editor/ui/button/index.ts b/svelte-inline-menu/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-inline-menu/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-inline-menu/src/components/editor/ui/inline-menu/index.ts b/svelte-inline-menu/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..bf78dd2139 --- /dev/null +++ b/svelte-inline-menu/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-inline-menu/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-inline-menu/src/components/editor/ui/inline-menu/inline-menu.svelte new file mode 100644 index 0000000000..989f0c013b --- /dev/null +++ b/svelte-inline-menu/src/components/editor/ui/inline-menu/inline-menu.svelte @@ -0,0 +1,207 @@ + + + { + if (!event.detail) linkMenuOpen = false + }} +> + + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.link?.canExec && $items.link} + + {/if} + + + + + { + linkMenuOpen = event.detail + }} +> + + + {#if linkMenuOpen && $items.link} +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ {/if} + {#if $items.link?.isActive} + + {/if} +
+
+
diff --git a/svelte-inline-menu/src/main.ts b/svelte-inline-menu/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-inline-menu/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-inline-menu/src/vite-env.d.ts b/svelte-inline-menu/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-inline-menu/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-inline-menu/svelte.config.js b/svelte-inline-menu/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-inline-menu/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-inline-menu/tsconfig.json b/svelte-inline-menu/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-inline-menu/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-inline-menu/tsconfig.node.json b/svelte-inline-menu/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-inline-menu/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-inline-menu/vite.config.ts b/svelte-inline-menu/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-inline-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-italic/.gitignore b/svelte-italic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-italic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-italic/README.md b/svelte-italic/README.md new file mode 100644 index 0000000000..26fe8e485b --- /dev/null +++ b/svelte-italic/README.md @@ -0,0 +1,15 @@ +# svelte-italic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-italic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-italic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-italic svelte-italic +cd svelte-italic +npm install +npm run dev +``` diff --git a/svelte-italic/index.html b/svelte-italic/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-italic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-italic/package.json b/svelte-italic/package.json new file mode 100644 index 0000000000..6498231129 --- /dev/null +++ b/svelte-italic/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-italic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-italic/src/App.svelte b/svelte-italic/src/App.svelte new file mode 100644 index 0000000000..3a23fc7410 --- /dev/null +++ b/svelte-italic/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-italic/src/app.css b/svelte-italic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-italic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-italic/src/components/editor/examples/italic/editor.svelte b/svelte-italic/src/components/editor/examples/italic/editor.svelte new file mode 100644 index 0000000000..2b3d9d8c5b --- /dev/null +++ b/svelte-italic/src/components/editor/examples/italic/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-italic/src/components/editor/examples/italic/extension.ts b/svelte-italic/src/components/editor/examples/italic/extension.ts new file mode 100644 index 0000000000..a456b06aad --- /dev/null +++ b/svelte-italic/src/components/editor/examples/italic/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineItalic(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-italic/src/components/editor/examples/italic/index.ts b/svelte-italic/src/components/editor/examples/italic/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-italic/src/components/editor/examples/italic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-italic/src/components/editor/sample/sample-doc-italic.ts b/svelte-italic/src/components/editor/sample/sample-doc-italic.ts new file mode 100644 index 0000000000..fb99415b2c --- /dev/null +++ b/svelte-italic/src/components/editor/sample/sample-doc-italic.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/svelte-italic/src/components/editor/ui/button/button.svelte b/svelte-italic/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-italic/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-italic/src/components/editor/ui/button/index.ts b/svelte-italic/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-italic/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-italic/src/components/editor/ui/image-upload-popover/index.ts b/svelte-italic/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-italic/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-italic/src/components/editor/ui/toolbar/index.ts b/svelte-italic/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-italic/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-italic/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-italic/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-italic/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-italic/src/main.ts b/svelte-italic/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-italic/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-italic/src/vite-env.d.ts b/svelte-italic/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-italic/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-italic/svelte.config.js b/svelte-italic/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-italic/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-italic/tsconfig.json b/svelte-italic/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-italic/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-italic/tsconfig.node.json b/svelte-italic/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-italic/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-italic/vite.config.ts b/svelte-italic/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-italic/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-katex/.gitignore b/svelte-katex/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-katex/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-katex/README.md b/svelte-katex/README.md new file mode 100644 index 0000000000..2a7247175a --- /dev/null +++ b/svelte-katex/README.md @@ -0,0 +1,15 @@ +# svelte-katex + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-katex) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-katex) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-katex svelte-katex +cd svelte-katex +npm install +npm run dev +``` diff --git a/svelte-katex/index.html b/svelte-katex/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-katex/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-katex/package.json b/svelte-katex/package.json new file mode 100644 index 0000000000..17a605a9c0 --- /dev/null +++ b/svelte-katex/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-svelte-katex", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-katex/src/App.svelte b/svelte-katex/src/App.svelte new file mode 100644 index 0000000000..8b059f290e --- /dev/null +++ b/svelte-katex/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-katex/src/app.css b/svelte-katex/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-katex/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-katex/src/components/editor/examples/katex/editor.svelte b/svelte-katex/src/components/editor/examples/katex/editor.svelte new file mode 100644 index 0000000000..b4f078fbb4 --- /dev/null +++ b/svelte-katex/src/components/editor/examples/katex/editor.svelte @@ -0,0 +1,28 @@ + + + +
+
+
+
+
+
diff --git a/svelte-katex/src/components/editor/examples/katex/extension.ts b/svelte-katex/src/components/editor/examples/katex/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/svelte-katex/src/components/editor/examples/katex/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-katex/src/components/editor/examples/katex/index.ts b/svelte-katex/src/components/editor/examples/katex/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-katex/src/components/editor/examples/katex/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-katex/src/components/editor/sample/katex.ts b/svelte-katex/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/svelte-katex/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/svelte-katex/src/components/editor/sample/sample-doc-tex.ts b/svelte-katex/src/components/editor/sample/sample-doc-tex.ts new file mode 100644 index 0000000000..21ccf3e94e --- /dev/null +++ b/svelte-katex/src/components/editor/sample/sample-doc-tex.ts @@ -0,0 +1,60 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Inline equations' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Block equations' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: 'The Gaussian integral:' }], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + ], +} diff --git a/svelte-katex/src/main.ts b/svelte-katex/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-katex/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-katex/src/vite-env.d.ts b/svelte-katex/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-katex/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-katex/svelte.config.js b/svelte-katex/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-katex/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-katex/tsconfig.json b/svelte-katex/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-katex/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-katex/tsconfig.node.json b/svelte-katex/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-katex/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-katex/vite.config.ts b/svelte-katex/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-katex/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-keymap/.gitignore b/svelte-keymap/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-keymap/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-keymap/README.md b/svelte-keymap/README.md new file mode 100644 index 0000000000..f1576889da --- /dev/null +++ b/svelte-keymap/README.md @@ -0,0 +1,15 @@ +# svelte-keymap + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-keymap) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-keymap) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-keymap svelte-keymap +cd svelte-keymap +npm install +npm run dev +``` diff --git a/svelte-keymap/index.html b/svelte-keymap/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-keymap/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-keymap/package.json b/svelte-keymap/package.json new file mode 100644 index 0000000000..b3d9d56c55 --- /dev/null +++ b/svelte-keymap/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-keymap", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-keymap/src/App.svelte b/svelte-keymap/src/App.svelte new file mode 100644 index 0000000000..d8811f6ba4 --- /dev/null +++ b/svelte-keymap/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-keymap/src/app.css b/svelte-keymap/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-keymap/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-keymap/src/components/editor/examples/keymap/editor.svelte b/svelte-keymap/src/components/editor/examples/keymap/editor.svelte new file mode 100644 index 0000000000..c6e4e13718 --- /dev/null +++ b/svelte-keymap/src/components/editor/examples/keymap/editor.svelte @@ -0,0 +1,43 @@ + + + +
+ +
+
+
+
+
+ Submit Records +
    + {#each submissions as submission, index (index)} +
  1. +
    {submission}
    +
  2. + {/each} +
+ {#if submissions.length === 0} +
No submissions yet
+ {/if} +
+
diff --git a/svelte-keymap/src/components/editor/examples/keymap/extension.ts b/svelte-keymap/src/components/editor/examples/keymap/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/svelte-keymap/src/components/editor/examples/keymap/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/svelte-keymap/src/components/editor/examples/keymap/index.ts b/svelte-keymap/src/components/editor/examples/keymap/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-keymap/src/components/editor/examples/keymap/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-keymap/src/components/editor/examples/keymap/toolbar.svelte b/svelte-keymap/src/components/editor/examples/keymap/toolbar.svelte new file mode 100644 index 0000000000..248e0deb50 --- /dev/null +++ b/svelte-keymap/src/components/editor/examples/keymap/toolbar.svelte @@ -0,0 +1,45 @@ + + +
+ + + +
diff --git a/svelte-keymap/src/components/editor/ui/button/button.svelte b/svelte-keymap/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-keymap/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-keymap/src/components/editor/ui/button/index.ts b/svelte-keymap/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-keymap/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-keymap/src/main.ts b/svelte-keymap/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-keymap/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-keymap/src/vite-env.d.ts b/svelte-keymap/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-keymap/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-keymap/svelte.config.js b/svelte-keymap/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-keymap/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-keymap/tsconfig.json b/svelte-keymap/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-keymap/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-keymap/tsconfig.node.json b/svelte-keymap/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-keymap/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-keymap/vite.config.ts b/svelte-keymap/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-keymap/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-link-mark-view/.gitignore b/svelte-link-mark-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-link-mark-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-link-mark-view/README.md b/svelte-link-mark-view/README.md new file mode 100644 index 0000000000..59aadd7f51 --- /dev/null +++ b/svelte-link-mark-view/README.md @@ -0,0 +1,15 @@ +# svelte-link-mark-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-link-mark-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-link-mark-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-link-mark-view svelte-link-mark-view +cd svelte-link-mark-view +npm install +npm run dev +``` diff --git a/svelte-link-mark-view/index.html b/svelte-link-mark-view/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-link-mark-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-link-mark-view/package.json b/svelte-link-mark-view/package.json new file mode 100644 index 0000000000..ae839bbd8f --- /dev/null +++ b/svelte-link-mark-view/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-link-mark-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-link-mark-view/src/App.svelte b/svelte-link-mark-view/src/App.svelte new file mode 100644 index 0000000000..84ff419f29 --- /dev/null +++ b/svelte-link-mark-view/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-link-mark-view/src/app.css b/svelte-link-mark-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-link-mark-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/editor.svelte b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/editor.svelte new file mode 100644 index 0000000000..b6efd2c7f7 --- /dev/null +++ b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/editor.svelte @@ -0,0 +1,28 @@ + + + +
+
+
+
+
+
diff --git a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts new file mode 100644 index 0000000000..93e37e9334 --- /dev/null +++ b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineSvelteMarkView } from 'prosekit/svelte' + +import LinkView from './link-view.svelte' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineSvelteMarkView({ + name: 'link', + component: LinkView, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-link-mark-view/src/components/editor/examples/link-mark-view/link-view.svelte b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/link-view.svelte new file mode 100644 index 0000000000..9aea6240ff --- /dev/null +++ b/svelte-link-mark-view/src/components/editor/examples/link-mark-view/link-view.svelte @@ -0,0 +1,50 @@ + + + + diff --git a/svelte-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/svelte-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts new file mode 100644 index 0000000000..57abd09dd6 --- /dev/null +++ b/svelte-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is a link that changes color every second: ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/svelte-link-mark-view/src/main.ts b/svelte-link-mark-view/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-link-mark-view/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-link-mark-view/src/vite-env.d.ts b/svelte-link-mark-view/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-link-mark-view/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-link-mark-view/svelte.config.js b/svelte-link-mark-view/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-link-mark-view/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-link-mark-view/tsconfig.json b/svelte-link-mark-view/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-link-mark-view/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-link-mark-view/tsconfig.node.json b/svelte-link-mark-view/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-link-mark-view/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-link-mark-view/vite.config.ts b/svelte-link-mark-view/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-link-mark-view/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-link/.gitignore b/svelte-link/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-link/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-link/README.md b/svelte-link/README.md new file mode 100644 index 0000000000..0f32085730 --- /dev/null +++ b/svelte-link/README.md @@ -0,0 +1,15 @@ +# svelte-link + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-link) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-link) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-link svelte-link +cd svelte-link +npm install +npm run dev +``` diff --git a/svelte-link/index.html b/svelte-link/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-link/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-link/package.json b/svelte-link/package.json new file mode 100644 index 0000000000..834b75a5c3 --- /dev/null +++ b/svelte-link/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-link", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-link/src/App.svelte b/svelte-link/src/App.svelte new file mode 100644 index 0000000000..1ad5cdd8dd --- /dev/null +++ b/svelte-link/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-link/src/app.css b/svelte-link/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-link/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-link/src/components/editor/examples/link/editor.svelte b/svelte-link/src/components/editor/examples/link/editor.svelte new file mode 100644 index 0000000000..92d4a9816c --- /dev/null +++ b/svelte-link/src/components/editor/examples/link/editor.svelte @@ -0,0 +1,30 @@ + + + +
+
+
+ +
+
+
diff --git a/svelte-link/src/components/editor/examples/link/extension.ts b/svelte-link/src/components/editor/examples/link/extension.ts new file mode 100644 index 0000000000..bf499147da --- /dev/null +++ b/svelte-link/src/components/editor/examples/link/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLink } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-link/src/components/editor/examples/link/index.ts b/svelte-link/src/components/editor/examples/link/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-link/src/components/editor/examples/link/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-link/src/components/editor/sample/sample-doc-link.ts b/svelte-link/src/components/editor/sample/sample-doc-link.ts new file mode 100644 index 0000000000..726cf334fd --- /dev/null +++ b/svelte-link/src/components/editor/sample/sample-doc-link.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is an ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/svelte-link/src/components/editor/ui/button/button.svelte b/svelte-link/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-link/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-link/src/components/editor/ui/button/index.ts b/svelte-link/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-link/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-link/src/components/editor/ui/inline-menu/index.ts b/svelte-link/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..bf78dd2139 --- /dev/null +++ b/svelte-link/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-link/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-link/src/components/editor/ui/inline-menu/inline-menu.svelte new file mode 100644 index 0000000000..989f0c013b --- /dev/null +++ b/svelte-link/src/components/editor/ui/inline-menu/inline-menu.svelte @@ -0,0 +1,207 @@ + + + { + if (!event.detail) linkMenuOpen = false + }} +> + + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.link?.canExec && $items.link} + + {/if} + + + + + { + linkMenuOpen = event.detail + }} +> + + + {#if linkMenuOpen && $items.link} +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ {/if} + {#if $items.link?.isActive} + + {/if} +
+
+
diff --git a/svelte-link/src/main.ts b/svelte-link/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-link/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-link/src/vite-env.d.ts b/svelte-link/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-link/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-link/svelte.config.js b/svelte-link/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-link/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-link/tsconfig.json b/svelte-link/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-link/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-link/tsconfig.node.json b/svelte-link/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-link/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-link/vite.config.ts b/svelte-link/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-link/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-list-custom-checkbox/.gitignore b/svelte-list-custom-checkbox/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-list-custom-checkbox/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-list-custom-checkbox/README.md b/svelte-list-custom-checkbox/README.md new file mode 100644 index 0000000000..760db805cb --- /dev/null +++ b/svelte-list-custom-checkbox/README.md @@ -0,0 +1,15 @@ +# svelte-list-custom-checkbox + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-list-custom-checkbox) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-list-custom-checkbox) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-list-custom-checkbox svelte-list-custom-checkbox +cd svelte-list-custom-checkbox +npm install +npm run dev +``` diff --git a/svelte-list-custom-checkbox/index.html b/svelte-list-custom-checkbox/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-list-custom-checkbox/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-list-custom-checkbox/package.json b/svelte-list-custom-checkbox/package.json new file mode 100644 index 0000000000..6b6dc48675 --- /dev/null +++ b/svelte-list-custom-checkbox/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-list-custom-checkbox", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-list-custom-checkbox/src/App.svelte b/svelte-list-custom-checkbox/src/App.svelte new file mode 100644 index 0000000000..408fa4ea3f --- /dev/null +++ b/svelte-list-custom-checkbox/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-list-custom-checkbox/src/app.css b/svelte-list-custom-checkbox/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-list-custom-checkbox/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css new file mode 100644 index 0000000000..ec631b72ad --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css @@ -0,0 +1,75 @@ +div[data-custom-list-css-enabled] + .ProseMirror + .prosemirror-flat-list[data-list-kind='task'] { + & > .list-marker label { + box-sizing: border-box; + display: flex; + position: relative; + left: calc(var(--spacing) * -0.5); + align-items: center; + cursor: pointer; + transition: transform 0.15s ease-in-out; + + &:hover { + transform: scale(1.1); + } + + &::after { + position: absolute; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + content: ''; + color: var(--color-white); + opacity: 0; + } + + /* https://api.iconify.design/lucide.css?icons=check */ + &::after { + display: inline-block; + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); + } + + & input { + box-sizing: border-box; + appearance: none; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + margin: 0; + border-width: 1px; + border-style: solid; + border-radius: var(--radius-md); + border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); + box-shadow: var(--shadow-sm); + cursor: pointer; + transition: all 0.15s ease-in-out; + + &:hover { + box-shadow: var(--shadow-md); + } + + &:checked { + border-color: var(--color-red-500); + background-color: var(--color-red-500); + } + } + } + + &[data-list-checked] > .list-marker label { + &::after { + opacity: 1; + } + } + + &[data-list-checked] { + color: var(--color-gray-400); + text-decoration: line-through; + text-decoration-color: var(--color-gray-400); + } +} diff --git a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.svelte b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.svelte new file mode 100644 index 0000000000..d0cc93914f --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.svelte @@ -0,0 +1,31 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/svelte-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts new file mode 100644 index 0000000000..972611aed1 --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts @@ -0,0 +1,38 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', + }, + { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, + { type: 'text', text: ' for the styles.' }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Completed Task' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Incomplete Task' }], + }, + ], + }, + ], +} diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/button/button.svelte b/svelte-list-custom-checkbox/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/button/index.ts b/svelte-list-custom-checkbox/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-list-custom-checkbox/src/main.ts b/svelte-list-custom-checkbox/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-list-custom-checkbox/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-list-custom-checkbox/src/vite-env.d.ts b/svelte-list-custom-checkbox/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-list-custom-checkbox/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-list-custom-checkbox/svelte.config.js b/svelte-list-custom-checkbox/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-list-custom-checkbox/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-list-custom-checkbox/tsconfig.json b/svelte-list-custom-checkbox/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-list-custom-checkbox/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-list-custom-checkbox/tsconfig.node.json b/svelte-list-custom-checkbox/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-list-custom-checkbox/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-list-custom-checkbox/vite.config.ts b/svelte-list-custom-checkbox/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-list-custom-checkbox/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-list/.gitignore b/svelte-list/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-list/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-list/README.md b/svelte-list/README.md new file mode 100644 index 0000000000..f943199072 --- /dev/null +++ b/svelte-list/README.md @@ -0,0 +1,15 @@ +# svelte-list + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-list) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-list) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-list svelte-list +cd svelte-list +npm install +npm run dev +``` diff --git a/svelte-list/index.html b/svelte-list/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-list/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-list/package.json b/svelte-list/package.json new file mode 100644 index 0000000000..3da32eeb9a --- /dev/null +++ b/svelte-list/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-list", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-list/src/App.svelte b/svelte-list/src/App.svelte new file mode 100644 index 0000000000..540d0595d0 --- /dev/null +++ b/svelte-list/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-list/src/app.css b/svelte-list/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-list/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-list/src/components/editor/examples/list/editor.svelte b/svelte-list/src/components/editor/examples/list/editor.svelte new file mode 100644 index 0000000000..f148dbea23 --- /dev/null +++ b/svelte-list/src/components/editor/examples/list/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-list/src/components/editor/examples/list/extension.ts b/svelte-list/src/components/editor/examples/list/extension.ts new file mode 100644 index 0000000000..f66bae6ff7 --- /dev/null +++ b/svelte-list/src/components/editor/examples/list/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineList } from 'prosekit/extensions/list' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineList(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-list/src/components/editor/examples/list/index.ts b/svelte-list/src/components/editor/examples/list/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-list/src/components/editor/examples/list/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-list/src/components/editor/sample/sample-doc-list.ts b/svelte-list/src/components/editor/sample/sample-doc-list.ts new file mode 100644 index 0000000000..091bc37185 --- /dev/null +++ b/svelte-list/src/components/editor/sample/sample-doc-list.ts @@ -0,0 +1,47 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Ordered List' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'toggle', collapsed: true }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, + { + type: 'list', + attrs: { + kind: 'bullet', + }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, + ], + }, + ], + }, + ], +} diff --git a/svelte-list/src/components/editor/ui/button/button.svelte b/svelte-list/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-list/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-list/src/components/editor/ui/button/index.ts b/svelte-list/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-list/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-list/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-list/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-list/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-list/src/components/editor/ui/image-upload-popover/index.ts b/svelte-list/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-list/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-list/src/components/editor/ui/toolbar/index.ts b/svelte-list/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-list/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-list/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-list/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-list/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-list/src/main.ts b/svelte-list/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-list/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-list/src/vite-env.d.ts b/svelte-list/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-list/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-list/svelte.config.js b/svelte-list/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-list/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-list/tsconfig.json b/svelte-list/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-list/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-list/tsconfig.node.json b/svelte-list/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-list/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-list/vite.config.ts b/svelte-list/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-list/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-loro/.gitignore b/svelte-loro/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-loro/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-loro/README.md b/svelte-loro/README.md new file mode 100644 index 0000000000..01b4624a76 --- /dev/null +++ b/svelte-loro/README.md @@ -0,0 +1,15 @@ +# svelte-loro + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-loro) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-loro) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-loro svelte-loro +cd svelte-loro +npm install +npm run dev +``` diff --git a/svelte-loro/index.html b/svelte-loro/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-loro/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-loro/package.json b/svelte-loro/package.json new file mode 100644 index 0000000000..efc88ab0d5 --- /dev/null +++ b/svelte-loro/package.json @@ -0,0 +1,31 @@ +{ + "name": "example-svelte-loro", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "loro-crdt": "^1.12.1", + "loro-prosemirror": "^0.4.3", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-wasm": "^3.6.0" + } +} diff --git a/svelte-loro/src/App.svelte b/svelte-loro/src/App.svelte new file mode 100644 index 0000000000..e1c0eb1713 --- /dev/null +++ b/svelte-loro/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-loro/src/app.css b/svelte-loro/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-loro/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-loro/src/components/editor/examples/loro/editor-component.svelte b/svelte-loro/src/components/editor/examples/loro/editor-component.svelte new file mode 100644 index 0000000000..7d5be7ece2 --- /dev/null +++ b/svelte-loro/src/components/editor/examples/loro/editor-component.svelte @@ -0,0 +1,32 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-loro/src/components/editor/examples/loro/editor.svelte b/svelte-loro/src/components/editor/examples/loro/editor.svelte new file mode 100644 index 0000000000..0086564202 --- /dev/null +++ b/svelte-loro/src/components/editor/examples/loro/editor.svelte @@ -0,0 +1,55 @@ + + +
+ + +
diff --git a/svelte-loro/src/components/editor/examples/loro/extension.ts b/svelte-loro/src/components/editor/examples/loro/extension.ts new file mode 100644 index 0000000000..5b2380c7c9 --- /dev/null +++ b/svelte-loro/src/components/editor/examples/loro/extension.ts @@ -0,0 +1,47 @@ +import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineLoro } from 'prosekit/extensions/loro' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { + return union( + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineLoro({ doc, awareness }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-loro/src/components/editor/examples/loro/index.ts b/svelte-loro/src/components/editor/examples/loro/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-loro/src/components/editor/examples/loro/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-loro/src/components/editor/ui/button/button.svelte b/svelte-loro/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-loro/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-loro/src/components/editor/ui/button/index.ts b/svelte-loro/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-loro/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-loro/src/components/editor/ui/image-upload-popover/index.ts b/svelte-loro/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-loro/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-loro/src/components/editor/ui/toolbar/index.ts b/svelte-loro/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-loro/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-loro/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-loro/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-loro/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-loro/src/main.ts b/svelte-loro/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-loro/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-loro/src/vite-env.d.ts b/svelte-loro/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-loro/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-loro/svelte.config.js b/svelte-loro/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-loro/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-loro/tsconfig.json b/svelte-loro/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-loro/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-loro/tsconfig.node.json b/svelte-loro/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-loro/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-loro/vite.config.ts b/svelte-loro/vite.config.ts new file mode 100644 index 0000000000..d4fb669e14 --- /dev/null +++ b/svelte-loro/vite.config.ts @@ -0,0 +1,9 @@ +import wasm from 'vite-plugin-wasm' +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [wasm(), svelte(), tailwindcss()], +}) diff --git a/svelte-mark-rule/.gitignore b/svelte-mark-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-mark-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-mark-rule/README.md b/svelte-mark-rule/README.md new file mode 100644 index 0000000000..243502eb29 --- /dev/null +++ b/svelte-mark-rule/README.md @@ -0,0 +1,15 @@ +# svelte-mark-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-mark-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-mark-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-mark-rule svelte-mark-rule +cd svelte-mark-rule +npm install +npm run dev +``` diff --git a/svelte-mark-rule/index.html b/svelte-mark-rule/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-mark-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-mark-rule/package.json b/svelte-mark-rule/package.json new file mode 100644 index 0000000000..72b9ea835a --- /dev/null +++ b/svelte-mark-rule/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-mark-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-mark-rule/src/App.svelte b/svelte-mark-rule/src/App.svelte new file mode 100644 index 0000000000..2d590088e8 --- /dev/null +++ b/svelte-mark-rule/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-mark-rule/src/app.css b/svelte-mark-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-mark-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-mark-rule/src/components/editor/examples/mark-rule/editor.svelte b/svelte-mark-rule/src/components/editor/examples/mark-rule/editor.svelte new file mode 100644 index 0000000000..03b6c9f2ca --- /dev/null +++ b/svelte-mark-rule/src/components/editor/examples/mark-rule/editor.svelte @@ -0,0 +1,20 @@ + + + +
+
+
+
+
+
diff --git a/svelte-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/svelte-mark-rule/src/components/editor/examples/mark-rule/extension.ts new file mode 100644 index 0000000000..4a1de40783 --- /dev/null +++ b/svelte-mark-rule/src/components/editor/examples/mark-rule/extension.ts @@ -0,0 +1,32 @@ +import { + defineBaseCommands, + defineBaseKeymap, + defineHistory, + union, +} from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { definePlaceholder } from 'prosekit/extensions/placeholder' +import { defineText } from 'prosekit/extensions/text' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +import { defineIssueLink } from './issue-link' + +export function defineExtension() { + return union( + defineDoc(), + defineText(), + defineParagraph(), + defineHistory(), + defineBaseKeymap(), + defineBaseCommands(), + defineVirtualSelection(), + defineLinkSpec(), + defineLinkMarkRule(), + definePlaceholder({ placeholder: 'Try typing #123' }), + defineIssueLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-mark-rule/src/components/editor/examples/mark-rule/index.ts b/svelte-mark-rule/src/components/editor/examples/mark-rule/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-mark-rule/src/components/editor/examples/mark-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/svelte-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts new file mode 100644 index 0000000000..3840b5e53d --- /dev/null +++ b/svelte-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts @@ -0,0 +1,32 @@ +import { defineMarkSpec, union } from 'prosekit/core' +import { defineMarkRule } from 'prosekit/extensions/mark-rule' + +export function defineIssueLink() { + return union( + defineMarkSpec({ + name: 'issueLink', + inclusive: false, + attrs: { + issueNumber: {}, + }, + toDOM(node) { + const issueNumber = node.attrs.issueNumber as number + return [ + 'a', + { + href: `https://example.com/issues/${issueNumber}`, + title: `Issue #${issueNumber}`, + }, + 0, + ] + }, + }), + defineMarkRule({ + regex: /#(\d+)/g, + type: 'issueLink', + attrs: (match) => { + return { issueNumber: Number.parseInt(match[1] || '0') } + }, + }), + ) +} diff --git a/svelte-mark-rule/src/main.ts b/svelte-mark-rule/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-mark-rule/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-mark-rule/src/vite-env.d.ts b/svelte-mark-rule/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-mark-rule/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-mark-rule/svelte.config.js b/svelte-mark-rule/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-mark-rule/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-mark-rule/tsconfig.json b/svelte-mark-rule/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-mark-rule/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-mark-rule/tsconfig.node.json b/svelte-mark-rule/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-mark-rule/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-mark-rule/vite.config.ts b/svelte-mark-rule/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-mark-rule/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-minimal/.gitignore b/svelte-minimal/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-minimal/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-minimal/README.md b/svelte-minimal/README.md new file mode 100644 index 0000000000..d212c5f932 --- /dev/null +++ b/svelte-minimal/README.md @@ -0,0 +1,15 @@ +# svelte-minimal + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-minimal) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-minimal) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-minimal svelte-minimal +cd svelte-minimal +npm install +npm run dev +``` diff --git a/svelte-minimal/index.html b/svelte-minimal/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-minimal/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-minimal/package.json b/svelte-minimal/package.json new file mode 100644 index 0000000000..fed18d28d8 --- /dev/null +++ b/svelte-minimal/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-minimal/src/App.svelte b/svelte-minimal/src/App.svelte new file mode 100644 index 0000000000..e4e92350bf --- /dev/null +++ b/svelte-minimal/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-minimal/src/app.css b/svelte-minimal/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-minimal/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-minimal/src/components/editor/examples/minimal/editor.svelte b/svelte-minimal/src/components/editor/examples/minimal/editor.svelte new file mode 100644 index 0000000000..10f7602cb4 --- /dev/null +++ b/svelte-minimal/src/components/editor/examples/minimal/editor.svelte @@ -0,0 +1,15 @@ + + + +
+
diff --git a/svelte-minimal/src/components/editor/examples/minimal/index.ts b/svelte-minimal/src/components/editor/examples/minimal/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-minimal/src/components/editor/examples/minimal/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-minimal/src/main.ts b/svelte-minimal/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-minimal/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-minimal/src/vite-env.d.ts b/svelte-minimal/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-minimal/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-minimal/svelte.config.js b/svelte-minimal/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-minimal/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-minimal/tsconfig.json b/svelte-minimal/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-minimal/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-minimal/tsconfig.node.json b/svelte-minimal/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-minimal/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-minimal/vite.config.ts b/svelte-minimal/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-minimal/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-page/.gitignore b/svelte-page/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-page/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-page/README.md b/svelte-page/README.md new file mode 100644 index 0000000000..7a3acaae74 --- /dev/null +++ b/svelte-page/README.md @@ -0,0 +1,15 @@ +# svelte-page + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-page) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-page) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-page svelte-page +cd svelte-page +npm install +npm run dev +``` diff --git a/svelte-page/index.html b/svelte-page/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-page/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-page/package.json b/svelte-page/package.json new file mode 100644 index 0000000000..dd67b1d8ac --- /dev/null +++ b/svelte-page/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-page", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-page/src/App.svelte b/svelte-page/src/App.svelte new file mode 100644 index 0000000000..a6ae83118a --- /dev/null +++ b/svelte-page/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-page/src/app.css b/svelte-page/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-page/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-page/src/components/editor/examples/page/editor.svelte b/svelte-page/src/components/editor/examples/page/editor.svelte new file mode 100644 index 0000000000..258fa08c71 --- /dev/null +++ b/svelte-page/src/components/editor/examples/page/editor.svelte @@ -0,0 +1,38 @@ + + + +
+ +
+
+
+
diff --git a/svelte-page/src/components/editor/examples/page/extension.ts b/svelte-page/src/components/editor/examples/page/extension.ts new file mode 100644 index 0000000000..edf01e897b --- /dev/null +++ b/svelte-page/src/components/editor/examples/page/extension.ts @@ -0,0 +1,9 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePageBreak } from 'prosekit/extensions/page' + +export function defineExtension() { + return union(defineBasicExtension(), definePageBreak()) +} + +export type EditorExtension = ReturnType diff --git a/svelte-page/src/components/editor/examples/page/index.ts b/svelte-page/src/components/editor/examples/page/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-page/src/components/editor/examples/page/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-page/src/components/editor/examples/page/paper-controller.svelte b/svelte-page/src/components/editor/examples/page/paper-controller.svelte new file mode 100644 index 0000000000..f62022f2b6 --- /dev/null +++ b/svelte-page/src/components/editor/examples/page/paper-controller.svelte @@ -0,0 +1,143 @@ + + +
+ + + + + + + + + + +
diff --git a/svelte-page/src/components/editor/examples/page/zoom.css b/svelte-page/src/components/editor/examples/page/zoom.css new file mode 100644 index 0000000000..bd81302639 --- /dev/null +++ b/svelte-page/src/components/editor/examples/page/zoom.css @@ -0,0 +1,9 @@ +div[data-editor-zoom] { + zoom: var(--zoom); +} + +@media print { + div[data-editor-zoom] { + zoom: 1; + } +} diff --git a/svelte-page/src/components/editor/sample/sample-doc-page.ts b/svelte-page/src/components/editor/sample/sample-doc-page.ts new file mode 100644 index 0000000000..60e78ac18e --- /dev/null +++ b/svelte-page/src/components/editor/sample/sample-doc-page.ts @@ -0,0 +1,98 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Page Layout Demo' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is the first page.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The content below will be on a new page because of a page break. You can insert a page break by pressing Command+Enter on Mac or Ctrl+Enter on Windows and Linux.', + }, + ], + }, + { type: 'pageBreak' }, + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Page 2' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is the second page.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'When the content on a page exceeds the available height, it will automatically flow to the next page. This is similar to how traditional word processors like Microsoft Word handle pagination.', + }, + ], + }, + { type: 'image', attrs: { src: 'https://placehold.co/600x500' } }, + { type: 'image', attrs: { src: 'https://placehold.co/600x500' } }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The images above exceed the available height on the second page, so they automatically flow to the next page.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Known Limitation' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Page breaks only occur between block elements. A single block taller than the remaining space on the page will overflow to the next page rather than split. In other words, you cannot split a node like paragraph or a table across pages. The paragraph below demonstrates this.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'This is a very long paragraph that demonstrates the limitation of block-level pagination.', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [{ type: 'italic' }], + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.', + }, + ], + }, + ], +} diff --git a/svelte-page/src/main.ts b/svelte-page/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-page/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-page/src/vite-env.d.ts b/svelte-page/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-page/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-page/svelte.config.js b/svelte-page/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-page/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-page/tsconfig.json b/svelte-page/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-page/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-page/tsconfig.node.json b/svelte-page/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-page/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-page/vite.config.ts b/svelte-page/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-page/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-placeholder/.gitignore b/svelte-placeholder/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-placeholder/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-placeholder/README.md b/svelte-placeholder/README.md new file mode 100644 index 0000000000..bbdab9669b --- /dev/null +++ b/svelte-placeholder/README.md @@ -0,0 +1,15 @@ +# svelte-placeholder + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-placeholder) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-placeholder) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-placeholder svelte-placeholder +cd svelte-placeholder +npm install +npm run dev +``` diff --git a/svelte-placeholder/index.html b/svelte-placeholder/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-placeholder/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-placeholder/package.json b/svelte-placeholder/package.json new file mode 100644 index 0000000000..7c577ac9f3 --- /dev/null +++ b/svelte-placeholder/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-placeholder", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-placeholder/src/App.svelte b/svelte-placeholder/src/App.svelte new file mode 100644 index 0000000000..daf201f559 --- /dev/null +++ b/svelte-placeholder/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-placeholder/src/app.css b/svelte-placeholder/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-placeholder/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-placeholder/src/components/editor/examples/placeholder/editor.svelte b/svelte-placeholder/src/components/editor/examples/placeholder/editor.svelte new file mode 100644 index 0000000000..3cfe679b52 --- /dev/null +++ b/svelte-placeholder/src/components/editor/examples/placeholder/editor.svelte @@ -0,0 +1,31 @@ + + + +
+
+
+
+
+
diff --git a/svelte-placeholder/src/components/editor/examples/placeholder/extension.ts b/svelte-placeholder/src/components/editor/examples/placeholder/extension.ts new file mode 100644 index 0000000000..12d0ba26f4 --- /dev/null +++ b/svelte-placeholder/src/components/editor/examples/placeholder/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Type something...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-placeholder/src/components/editor/examples/placeholder/index.ts b/svelte-placeholder/src/components/editor/examples/placeholder/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-placeholder/src/components/editor/examples/placeholder/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-placeholder/src/main.ts b/svelte-placeholder/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-placeholder/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-placeholder/src/vite-env.d.ts b/svelte-placeholder/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-placeholder/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-placeholder/svelte.config.js b/svelte-placeholder/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-placeholder/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-placeholder/tsconfig.json b/svelte-placeholder/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-placeholder/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-placeholder/tsconfig.node.json b/svelte-placeholder/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-placeholder/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-placeholder/vite.config.ts b/svelte-placeholder/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-placeholder/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-readonly/.gitignore b/svelte-readonly/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-readonly/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-readonly/README.md b/svelte-readonly/README.md new file mode 100644 index 0000000000..df4ef2e36c --- /dev/null +++ b/svelte-readonly/README.md @@ -0,0 +1,15 @@ +# svelte-readonly + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-readonly) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-readonly) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-readonly svelte-readonly +cd svelte-readonly +npm install +npm run dev +``` diff --git a/svelte-readonly/index.html b/svelte-readonly/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-readonly/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-readonly/package.json b/svelte-readonly/package.json new file mode 100644 index 0000000000..12d586da2e --- /dev/null +++ b/svelte-readonly/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-readonly", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-readonly/src/App.svelte b/svelte-readonly/src/App.svelte new file mode 100644 index 0000000000..969fdf2360 --- /dev/null +++ b/svelte-readonly/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-readonly/src/app.css b/svelte-readonly/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-readonly/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-readonly/src/components/editor/examples/readonly/editor.svelte b/svelte-readonly/src/components/editor/examples/readonly/editor.svelte new file mode 100644 index 0000000000..1bee26c40a --- /dev/null +++ b/svelte-readonly/src/components/editor/examples/readonly/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-readonly/src/components/editor/examples/readonly/extension.ts b/svelte-readonly/src/components/editor/examples/readonly/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/svelte-readonly/src/components/editor/examples/readonly/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/svelte-readonly/src/components/editor/examples/readonly/index.ts b/svelte-readonly/src/components/editor/examples/readonly/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-readonly/src/components/editor/examples/readonly/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-readonly/src/components/editor/examples/readonly/toolbar.svelte b/svelte-readonly/src/components/editor/examples/readonly/toolbar.svelte new file mode 100644 index 0000000000..bbec4e4f76 --- /dev/null +++ b/svelte-readonly/src/components/editor/examples/readonly/toolbar.svelte @@ -0,0 +1,27 @@ + + +
+ + + +
diff --git a/svelte-readonly/src/components/editor/sample/sample-doc-readonly.ts b/svelte-readonly/src/components/editor/sample/sample-doc-readonly.ts new file mode 100644 index 0000000000..abd9e2c6ac --- /dev/null +++ b/svelte-readonly/src/components/editor/sample/sample-doc-readonly.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', + }, + ], + }, + ], +} diff --git a/svelte-readonly/src/components/editor/ui/button/button.svelte b/svelte-readonly/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-readonly/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-readonly/src/components/editor/ui/button/index.ts b/svelte-readonly/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-readonly/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-readonly/src/main.ts b/svelte-readonly/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-readonly/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-readonly/src/vite-env.d.ts b/svelte-readonly/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-readonly/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-readonly/svelte.config.js b/svelte-readonly/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-readonly/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-readonly/tsconfig.json b/svelte-readonly/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-readonly/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-readonly/tsconfig.node.json b/svelte-readonly/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-readonly/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-readonly/vite.config.ts b/svelte-readonly/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-readonly/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-rtl/.gitignore b/svelte-rtl/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-rtl/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-rtl/README.md b/svelte-rtl/README.md new file mode 100644 index 0000000000..818025e82b --- /dev/null +++ b/svelte-rtl/README.md @@ -0,0 +1,15 @@ +# svelte-rtl + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-rtl) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-rtl) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-rtl svelte-rtl +cd svelte-rtl +npm install +npm run dev +``` diff --git a/svelte-rtl/index.html b/svelte-rtl/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-rtl/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-rtl/package.json b/svelte-rtl/package.json new file mode 100644 index 0000000000..f5ab0ade68 --- /dev/null +++ b/svelte-rtl/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-rtl", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-rtl/src/App.svelte b/svelte-rtl/src/App.svelte new file mode 100644 index 0000000000..96c115496b --- /dev/null +++ b/svelte-rtl/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-rtl/src/app.css b/svelte-rtl/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-rtl/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-rtl/src/components/editor/examples/rtl/editor.svelte b/svelte-rtl/src/components/editor/examples/rtl/editor.svelte new file mode 100644 index 0000000000..a1ecfd2377 --- /dev/null +++ b/svelte-rtl/src/components/editor/examples/rtl/editor.svelte @@ -0,0 +1,40 @@ + + + +
+ +
+
+ + + + + +
+
+
diff --git a/svelte-rtl/src/components/editor/examples/rtl/index.ts b/svelte-rtl/src/components/editor/examples/rtl/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-rtl/src/components/editor/examples/rtl/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-rtl/src/components/editor/sample/sample-doc-rtl.ts b/svelte-rtl/src/components/editor/sample/sample-doc-rtl.ts new file mode 100644 index 0000000000..696e797724 --- /dev/null +++ b/svelte-rtl/src/components/editor/sample/sample-doc-rtl.ts @@ -0,0 +1,187 @@ +import type { NodeJSON } from 'prosekit/core' + +const translation = { + Paragraph: 'فقرة', + 'Root list item': 'عنصر قائمة جذري', + 'Sub list item': 'عنصر قائمة فرعي', + 'Completed task': 'مهمة مكتملة', + 'Pending task': 'مهمة قيد الانتظار', + Quote: 'اقتباس', +} as const + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Right to Left' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Paragraph'] }], + }, + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Root list item'] }], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Completed task'] }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Pending task'] }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: 'hello world', + }, + ], + }, + + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, + ], + }, + ], + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: translation['Quote'], + }, + ], + }, + ], + }, + ], +} diff --git a/svelte-rtl/src/components/editor/sample/sample-uploader.ts b/svelte-rtl/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/svelte-rtl/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/svelte-rtl/src/components/editor/ui/block-handle/block-handle.svelte b/svelte-rtl/src/components/editor/ui/block-handle/block-handle.svelte new file mode 100644 index 0000000000..f67e42dc91 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/block-handle/block-handle.svelte @@ -0,0 +1,28 @@ + + + + + + +
+
+ +
+
+
+
+
diff --git a/svelte-rtl/src/components/editor/ui/block-handle/index.ts b/svelte-rtl/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..6d21191384 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.svelte' diff --git a/svelte-rtl/src/components/editor/ui/button/button.svelte b/svelte-rtl/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-rtl/src/components/editor/ui/button/index.ts b/svelte-rtl/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-rtl/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/svelte-rtl/src/components/editor/ui/drop-indicator/drop-indicator.svelte new file mode 100644 index 0000000000..7f6cac1db0 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/drop-indicator/drop-indicator.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-rtl/src/components/editor/ui/drop-indicator/index.ts b/svelte-rtl/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..06e89357ed --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator.svelte' diff --git a/svelte-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-rtl/src/components/editor/ui/image-upload-popover/index.ts b/svelte-rtl/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-rtl/src/components/editor/ui/inline-menu/index.ts b/svelte-rtl/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..bf78dd2139 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-rtl/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-rtl/src/components/editor/ui/inline-menu/inline-menu.svelte new file mode 100644 index 0000000000..989f0c013b --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/inline-menu/inline-menu.svelte @@ -0,0 +1,207 @@ + + + { + if (!event.detail) linkMenuOpen = false + }} +> + + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.link?.canExec && $items.link} + + {/if} + + + + + { + linkMenuOpen = event.detail + }} +> + + + {#if linkMenuOpen && $items.link} +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ {/if} + {#if $items.link?.isActive} + + {/if} +
+
+
diff --git a/svelte-rtl/src/components/editor/ui/slash-menu/index.ts b/svelte-rtl/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..856d4e6b43 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu.svelte' diff --git a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.svelte b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.svelte new file mode 100644 index 0000000000..37cea8de67 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.svelte @@ -0,0 +1,7 @@ + + + + No results + diff --git a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-item.svelte b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-item.svelte new file mode 100644 index 0000000000..52126eeb68 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu-item.svelte @@ -0,0 +1,15 @@ + + + + {props.label}{#if props.kbd}{props.kbd}{/if} + diff --git a/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu.svelte b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu.svelte new file mode 100644 index 0000000000..5da516b44f --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/slash-menu/slash-menu.svelte @@ -0,0 +1,94 @@ + + + + + +
+ $editor.commands.setParagraph()} + /> + + $editor.commands.setHeading({ level: 1 })} + /> + + $editor.commands.setHeading({ level: 2 })} + /> + + $editor.commands.setHeading({ level: 3 })} + /> + + $editor.commands.wrapInList({ kind: 'bullet' })} + /> + + $editor.commands.wrapInList({ kind: 'ordered' })} + /> + + $editor.commands.wrapInList({ kind: 'task' })} + /> + + $editor.commands.wrapInList({ kind: 'toggle' })} + /> + + $editor.commands.setBlockquote()} + /> + + $editor.commands.insertTable({ row: 3, col: 3 })} + /> + + $editor.commands.insertHorizontalRule()} + /> + + $editor.commands.setCodeBlock()} + /> + + +
+
+
+
diff --git a/svelte-rtl/src/components/editor/ui/table-handle/index.ts b/svelte-rtl/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..308cef59de --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle.svelte' diff --git a/svelte-rtl/src/components/editor/ui/table-handle/table-handle.svelte b/svelte-rtl/src/components/editor/ui/table-handle/table-handle.svelte new file mode 100644 index 0000000000..fc91f9a438 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/table-handle/table-handle.svelte @@ -0,0 +1,182 @@ + + + + + + + + + +
+
+ + + {#if $state.addTableColumnBefore.canExec} + + Insert Left + + {/if} + {#if $state.addTableColumnAfter.canExec} + + Insert Right + + {/if} + {#if $state.deleteCellSelection.canExec} + + Clear Contents + Del + + {/if} + {#if $state.deleteTableColumn.canExec} + + Delete Column + + {/if} + {#if $state.deleteTable.canExec} + + Delete Table + + {/if} + + +
+
+
+ + + + +
+
+ + + {#if $state.addTableRowAbove.canExec} + + Insert Above + + {/if} + {#if $state.addTableRowBelow.canExec} + + Insert Below + + {/if} + {#if $state.deleteCellSelection.canExec} + + Clear Contents + Del + + {/if} + {#if $state.deleteTableRow.canExec} + + Delete Row + + {/if} + {#if $state.deleteTable.canExec} + + Delete Table + + {/if} + + +
+
+
+
diff --git a/svelte-rtl/src/components/editor/ui/toolbar/index.ts b/svelte-rtl/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-rtl/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-rtl/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-rtl/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-rtl/src/main.ts b/svelte-rtl/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-rtl/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-rtl/src/vite-env.d.ts b/svelte-rtl/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-rtl/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-rtl/svelte.config.js b/svelte-rtl/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-rtl/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-rtl/tsconfig.json b/svelte-rtl/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-rtl/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-rtl/tsconfig.node.json b/svelte-rtl/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-rtl/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-rtl/vite.config.ts b/svelte-rtl/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-rtl/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-save-html/.gitignore b/svelte-save-html/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-save-html/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-save-html/README.md b/svelte-save-html/README.md new file mode 100644 index 0000000000..4519d57d39 --- /dev/null +++ b/svelte-save-html/README.md @@ -0,0 +1,15 @@ +# svelte-save-html + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-save-html) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-save-html) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-save-html svelte-save-html +cd svelte-save-html +npm install +npm run dev +``` diff --git a/svelte-save-html/index.html b/svelte-save-html/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-save-html/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-save-html/package.json b/svelte-save-html/package.json new file mode 100644 index 0000000000..97b0b99961 --- /dev/null +++ b/svelte-save-html/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-save-html", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-save-html/src/App.svelte b/svelte-save-html/src/App.svelte new file mode 100644 index 0000000000..9505ae9dd8 --- /dev/null +++ b/svelte-save-html/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-save-html/src/app.css b/svelte-save-html/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-save-html/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-save-html/src/components/editor/examples/save-html/editor.svelte b/svelte-save-html/src/components/editor/examples/save-html/editor.svelte new file mode 100644 index 0000000000..6cab449c13 --- /dev/null +++ b/svelte-save-html/src/components/editor/examples/save-html/editor.svelte @@ -0,0 +1,67 @@ + + +
+ +
    + {#each records as record, index (index)} +
  • + + +
    {record}
    +
    +
  • + {/each} +
+ {#key key} + +
+
+
+
+ {/key} +
diff --git a/svelte-save-html/src/components/editor/examples/save-html/index.ts b/svelte-save-html/src/components/editor/examples/save-html/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-save-html/src/components/editor/examples/save-html/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-save-html/src/main.ts b/svelte-save-html/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-save-html/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-save-html/src/vite-env.d.ts b/svelte-save-html/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-save-html/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-save-html/svelte.config.js b/svelte-save-html/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-save-html/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-save-html/tsconfig.json b/svelte-save-html/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-save-html/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-save-html/tsconfig.node.json b/svelte-save-html/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-save-html/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-save-html/vite.config.ts b/svelte-save-html/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-save-html/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-save-json/.gitignore b/svelte-save-json/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-save-json/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-save-json/README.md b/svelte-save-json/README.md new file mode 100644 index 0000000000..890e8c9c4d --- /dev/null +++ b/svelte-save-json/README.md @@ -0,0 +1,15 @@ +# svelte-save-json + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-save-json) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-save-json) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-save-json svelte-save-json +cd svelte-save-json +npm install +npm run dev +``` diff --git a/svelte-save-json/index.html b/svelte-save-json/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-save-json/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-save-json/package.json b/svelte-save-json/package.json new file mode 100644 index 0000000000..c75b6ba56d --- /dev/null +++ b/svelte-save-json/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-save-json", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-save-json/src/App.svelte b/svelte-save-json/src/App.svelte new file mode 100644 index 0000000000..33dcb8119d --- /dev/null +++ b/svelte-save-json/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-save-json/src/app.css b/svelte-save-json/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-save-json/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-save-json/src/components/editor/examples/save-json/editor.svelte b/svelte-save-json/src/components/editor/examples/save-json/editor.svelte new file mode 100644 index 0000000000..07d3415695 --- /dev/null +++ b/svelte-save-json/src/components/editor/examples/save-json/editor.svelte @@ -0,0 +1,67 @@ + + +
+ +
    + {#each records as record, index (index)} +
  • + + +
    {record}
    +
    +
  • + {/each} +
+ {#key key} + +
+
+
+
+ {/key} +
diff --git a/svelte-save-json/src/components/editor/examples/save-json/index.ts b/svelte-save-json/src/components/editor/examples/save-json/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-save-json/src/components/editor/examples/save-json/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-save-json/src/main.ts b/svelte-save-json/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-save-json/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-save-json/src/vite-env.d.ts b/svelte-save-json/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-save-json/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-save-json/svelte.config.js b/svelte-save-json/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-save-json/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-save-json/tsconfig.json b/svelte-save-json/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-save-json/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-save-json/tsconfig.node.json b/svelte-save-json/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-save-json/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-save-json/vite.config.ts b/svelte-save-json/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-save-json/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-save-markdown/.gitignore b/svelte-save-markdown/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-save-markdown/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-save-markdown/README.md b/svelte-save-markdown/README.md new file mode 100644 index 0000000000..95ae1a77a4 --- /dev/null +++ b/svelte-save-markdown/README.md @@ -0,0 +1,15 @@ +# svelte-save-markdown + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-save-markdown) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-save-markdown) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-save-markdown svelte-save-markdown +cd svelte-save-markdown +npm install +npm run dev +``` diff --git a/svelte-save-markdown/index.html b/svelte-save-markdown/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-save-markdown/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-save-markdown/package.json b/svelte-save-markdown/package.json new file mode 100644 index 0000000000..e051af2402 --- /dev/null +++ b/svelte-save-markdown/package.json @@ -0,0 +1,35 @@ +{ + "name": "example-svelte-save-markdown", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "rehype-parse": "^9.0.1", + "rehype-remark": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-html": "^16.0.1", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.5" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-save-markdown/src/App.svelte b/svelte-save-markdown/src/App.svelte new file mode 100644 index 0000000000..cdcdeb67ba --- /dev/null +++ b/svelte-save-markdown/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-save-markdown/src/app.css b/svelte-save-markdown/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-save-markdown/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-save-markdown/src/components/editor/examples/save-markdown/editor.svelte b/svelte-save-markdown/src/components/editor/examples/save-markdown/editor.svelte new file mode 100644 index 0000000000..79b78c9e1d --- /dev/null +++ b/svelte-save-markdown/src/components/editor/examples/save-markdown/editor.svelte @@ -0,0 +1,71 @@ + + +
+ +
    + {#each records as record, index (index)} +
  • + + +
    {record}
    +
    +
  • + {/each} +
+ {#key key} + +
+
+
+
+ {/key} +
diff --git a/svelte-save-markdown/src/components/editor/examples/save-markdown/index.ts b/svelte-save-markdown/src/components/editor/examples/save-markdown/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-save-markdown/src/components/editor/examples/save-markdown/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/svelte-save-markdown/src/components/editor/examples/save-markdown/markdown.ts new file mode 100644 index 0000000000..3f930adad2 --- /dev/null +++ b/svelte-save-markdown/src/components/editor/examples/save-markdown/markdown.ts @@ -0,0 +1,26 @@ +import rehypeParse from 'rehype-parse' +import rehypeRemark from 'rehype-remark' +import remarkGfm from 'remark-gfm' +import remarkHtml from 'remark-html' +import remarkParse from 'remark-parse' +import remarkStringify from 'remark-stringify' +import { unified } from 'unified' + +export function markdownFromHTML(html: string): string { + return unified() + .use(rehypeParse) + .use(rehypeRemark) + .use(remarkGfm) + .use(remarkStringify) + .processSync(html) + .toString() +} + +export function htmlFromMarkdown(markdown: string): string { + return unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkHtml) + .processSync(markdown) + .toString() +} diff --git a/svelte-save-markdown/src/main.ts b/svelte-save-markdown/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-save-markdown/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-save-markdown/src/vite-env.d.ts b/svelte-save-markdown/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-save-markdown/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-save-markdown/svelte.config.js b/svelte-save-markdown/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-save-markdown/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-save-markdown/tsconfig.json b/svelte-save-markdown/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-save-markdown/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-save-markdown/tsconfig.node.json b/svelte-save-markdown/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-save-markdown/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-save-markdown/vite.config.ts b/svelte-save-markdown/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-save-markdown/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-search/.gitignore b/svelte-search/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-search/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-search/README.md b/svelte-search/README.md new file mode 100644 index 0000000000..a43a9f9b3a --- /dev/null +++ b/svelte-search/README.md @@ -0,0 +1,15 @@ +# svelte-search + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-search) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-search) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-search svelte-search +cd svelte-search +npm install +npm run dev +``` diff --git a/svelte-search/index.html b/svelte-search/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-search/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-search/package.json b/svelte-search/package.json new file mode 100644 index 0000000000..7fa6f2caba --- /dev/null +++ b/svelte-search/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-search", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-search/src/App.svelte b/svelte-search/src/App.svelte new file mode 100644 index 0000000000..ab82613d74 --- /dev/null +++ b/svelte-search/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-search/src/app.css b/svelte-search/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-search/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-search/src/components/editor/examples/search/editor.svelte b/svelte-search/src/components/editor/examples/search/editor.svelte new file mode 100644 index 0000000000..eb2ca32536 --- /dev/null +++ b/svelte-search/src/components/editor/examples/search/editor.svelte @@ -0,0 +1,31 @@ + + + +
+
+ +
+
+
+
diff --git a/svelte-search/src/components/editor/examples/search/extension.ts b/svelte-search/src/components/editor/examples/search/extension.ts new file mode 100644 index 0000000000..10ff13f614 --- /dev/null +++ b/svelte-search/src/components/editor/examples/search/extension.ts @@ -0,0 +1,9 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineSearchCommands } from 'prosekit/extensions/search' + +export function defineExtension() { + return union(defineBasicExtension(), defineSearchCommands()) +} + +export type EditorExtension = ReturnType diff --git a/svelte-search/src/components/editor/examples/search/index.ts b/svelte-search/src/components/editor/examples/search/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-search/src/components/editor/examples/search/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-search/src/components/editor/sample/sample-doc-search.ts b/svelte-search/src/components/editor/sample/sample-doc-search.ts new file mode 100644 index 0000000000..c8160cca2a --- /dev/null +++ b/svelte-search/src/components/editor/sample/sample-doc-search.ts @@ -0,0 +1,79 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Baa, baa, black sheep,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Have you any wool?', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Yes, sir, yes, sir,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Three bags full;', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'One for the master,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the dame,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the little boy', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Who lives down the lane.', + }, + ], + }, + ], +} diff --git a/svelte-search/src/components/editor/ui/button/button.svelte b/svelte-search/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-search/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-search/src/components/editor/ui/button/index.ts b/svelte-search/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-search/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-search/src/components/editor/ui/search/index.ts b/svelte-search/src/components/editor/ui/search/index.ts new file mode 100644 index 0000000000..50dcb21701 --- /dev/null +++ b/svelte-search/src/components/editor/ui/search/index.ts @@ -0,0 +1 @@ +export { default as Search } from './search.svelte' diff --git a/svelte-search/src/components/editor/ui/search/search.svelte b/svelte-search/src/components/editor/ui/search/search.svelte new file mode 100644 index 0000000000..3daaa44de7 --- /dev/null +++ b/svelte-search/src/components/editor/ui/search/search.svelte @@ -0,0 +1,168 @@ + + +
+ + +
+ + + + + + + +
+ {#if showReplace} + +
+ + +
+ {/if} +
diff --git a/svelte-search/src/main.ts b/svelte-search/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-search/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-search/src/vite-env.d.ts b/svelte-search/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-search/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-search/svelte.config.js b/svelte-search/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-search/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-search/tsconfig.json b/svelte-search/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-search/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-search/tsconfig.node.json b/svelte-search/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-search/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-search/vite.config.ts b/svelte-search/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-search/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-slash-menu/.gitignore b/svelte-slash-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-slash-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-slash-menu/README.md b/svelte-slash-menu/README.md new file mode 100644 index 0000000000..3c23fb3df4 --- /dev/null +++ b/svelte-slash-menu/README.md @@ -0,0 +1,15 @@ +# svelte-slash-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-slash-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-slash-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-slash-menu svelte-slash-menu +cd svelte-slash-menu +npm install +npm run dev +``` diff --git a/svelte-slash-menu/index.html b/svelte-slash-menu/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-slash-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-slash-menu/package.json b/svelte-slash-menu/package.json new file mode 100644 index 0000000000..51a939eb16 --- /dev/null +++ b/svelte-slash-menu/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-slash-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-slash-menu/src/App.svelte b/svelte-slash-menu/src/App.svelte new file mode 100644 index 0000000000..629fa9a2c7 --- /dev/null +++ b/svelte-slash-menu/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-slash-menu/src/app.css b/svelte-slash-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-slash-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-slash-menu/src/components/editor/examples/slash-menu/editor.svelte b/svelte-slash-menu/src/components/editor/examples/slash-menu/editor.svelte new file mode 100644 index 0000000000..ba6f313174 --- /dev/null +++ b/svelte-slash-menu/src/components/editor/examples/slash-menu/editor.svelte @@ -0,0 +1,23 @@ + + + +
+
+
+ +
+
+
diff --git a/svelte-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/svelte-slash-menu/src/components/editor/examples/slash-menu/extension.ts new file mode 100644 index 0000000000..0edda60136 --- /dev/null +++ b/svelte-slash-menu/src/components/editor/examples/slash-menu/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-slash-menu/src/components/editor/examples/slash-menu/index.ts b/svelte-slash-menu/src/components/editor/examples/slash-menu/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-slash-menu/src/components/editor/examples/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-slash-menu/src/components/editor/ui/slash-menu/index.ts b/svelte-slash-menu/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..856d4e6b43 --- /dev/null +++ b/svelte-slash-menu/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu.svelte' diff --git a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.svelte b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.svelte new file mode 100644 index 0000000000..37cea8de67 --- /dev/null +++ b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.svelte @@ -0,0 +1,7 @@ + + + + No results + diff --git a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.svelte b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.svelte new file mode 100644 index 0000000000..52126eeb68 --- /dev/null +++ b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.svelte @@ -0,0 +1,15 @@ + + + + {props.label}{#if props.kbd}{props.kbd}{/if} + diff --git a/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu.svelte b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu.svelte new file mode 100644 index 0000000000..5da516b44f --- /dev/null +++ b/svelte-slash-menu/src/components/editor/ui/slash-menu/slash-menu.svelte @@ -0,0 +1,94 @@ + + + + + +
+ $editor.commands.setParagraph()} + /> + + $editor.commands.setHeading({ level: 1 })} + /> + + $editor.commands.setHeading({ level: 2 })} + /> + + $editor.commands.setHeading({ level: 3 })} + /> + + $editor.commands.wrapInList({ kind: 'bullet' })} + /> + + $editor.commands.wrapInList({ kind: 'ordered' })} + /> + + $editor.commands.wrapInList({ kind: 'task' })} + /> + + $editor.commands.wrapInList({ kind: 'toggle' })} + /> + + $editor.commands.setBlockquote()} + /> + + $editor.commands.insertTable({ row: 3, col: 3 })} + /> + + $editor.commands.insertHorizontalRule()} + /> + + $editor.commands.setCodeBlock()} + /> + + +
+
+
+
diff --git a/svelte-slash-menu/src/main.ts b/svelte-slash-menu/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-slash-menu/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-slash-menu/src/vite-env.d.ts b/svelte-slash-menu/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-slash-menu/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-slash-menu/svelte.config.js b/svelte-slash-menu/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-slash-menu/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-slash-menu/tsconfig.json b/svelte-slash-menu/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-slash-menu/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-slash-menu/tsconfig.node.json b/svelte-slash-menu/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-slash-menu/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-slash-menu/vite.config.ts b/svelte-slash-menu/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-slash-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-strike/.gitignore b/svelte-strike/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-strike/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-strike/README.md b/svelte-strike/README.md new file mode 100644 index 0000000000..306ffd4c85 --- /dev/null +++ b/svelte-strike/README.md @@ -0,0 +1,15 @@ +# svelte-strike + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-strike) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-strike) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-strike svelte-strike +cd svelte-strike +npm install +npm run dev +``` diff --git a/svelte-strike/index.html b/svelte-strike/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-strike/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-strike/package.json b/svelte-strike/package.json new file mode 100644 index 0000000000..9e2c6c2944 --- /dev/null +++ b/svelte-strike/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-strike", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-strike/src/App.svelte b/svelte-strike/src/App.svelte new file mode 100644 index 0000000000..27c31707c2 --- /dev/null +++ b/svelte-strike/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-strike/src/app.css b/svelte-strike/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-strike/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-strike/src/components/editor/examples/strike/editor.svelte b/svelte-strike/src/components/editor/examples/strike/editor.svelte new file mode 100644 index 0000000000..98cf2aa710 --- /dev/null +++ b/svelte-strike/src/components/editor/examples/strike/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-strike/src/components/editor/examples/strike/extension.ts b/svelte-strike/src/components/editor/examples/strike/extension.ts new file mode 100644 index 0000000000..c013303ccc --- /dev/null +++ b/svelte-strike/src/components/editor/examples/strike/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineStrike(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-strike/src/components/editor/examples/strike/index.ts b/svelte-strike/src/components/editor/examples/strike/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-strike/src/components/editor/examples/strike/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-strike/src/components/editor/examples/strike/toolbar.svelte b/svelte-strike/src/components/editor/examples/strike/toolbar.svelte new file mode 100644 index 0000000000..c8742e25f7 --- /dev/null +++ b/svelte-strike/src/components/editor/examples/strike/toolbar.svelte @@ -0,0 +1,30 @@ + + +
+ +
diff --git a/svelte-strike/src/components/editor/sample/sample-doc-strike.ts b/svelte-strike/src/components/editor/sample/sample-doc-strike.ts new file mode 100644 index 0000000000..2e025e9b02 --- /dev/null +++ b/svelte-strike/src/components/editor/sample/sample-doc-strike.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'This is strike', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/svelte-strike/src/components/editor/ui/button/button.svelte b/svelte-strike/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-strike/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-strike/src/components/editor/ui/button/index.ts b/svelte-strike/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-strike/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-strike/src/main.ts b/svelte-strike/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-strike/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-strike/src/vite-env.d.ts b/svelte-strike/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-strike/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-strike/svelte.config.js b/svelte-strike/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-strike/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-strike/tsconfig.json b/svelte-strike/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-strike/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-strike/tsconfig.node.json b/svelte-strike/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-strike/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-strike/vite.config.ts b/svelte-strike/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-strike/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-sub-sup/.gitignore b/svelte-sub-sup/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-sub-sup/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-sub-sup/README.md b/svelte-sub-sup/README.md new file mode 100644 index 0000000000..4259ee389e --- /dev/null +++ b/svelte-sub-sup/README.md @@ -0,0 +1,15 @@ +# svelte-sub-sup + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-sub-sup) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-sub-sup) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-sub-sup svelte-sub-sup +cd svelte-sub-sup +npm install +npm run dev +``` diff --git a/svelte-sub-sup/index.html b/svelte-sub-sup/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-sub-sup/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-sub-sup/package.json b/svelte-sub-sup/package.json new file mode 100644 index 0000000000..a98803cfab --- /dev/null +++ b/svelte-sub-sup/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-sub-sup", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-sub-sup/src/App.svelte b/svelte-sub-sup/src/App.svelte new file mode 100644 index 0000000000..0c05524f5f --- /dev/null +++ b/svelte-sub-sup/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-sub-sup/src/app.css b/svelte-sub-sup/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-sub-sup/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-sub-sup/src/components/editor/examples/sub-sup/editor.svelte b/svelte-sub-sup/src/components/editor/examples/sub-sup/editor.svelte new file mode 100644 index 0000000000..d70be85ed1 --- /dev/null +++ b/svelte-sub-sup/src/components/editor/examples/sub-sup/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/svelte-sub-sup/src/components/editor/examples/sub-sup/extension.ts new file mode 100644 index 0000000000..bd67245f86 --- /dev/null +++ b/svelte-sub-sup/src/components/editor/examples/sub-sup/extension.ts @@ -0,0 +1,32 @@ +import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineMarkInputRule } from 'prosekit/extensions/input-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineSubscript } from 'prosekit/extensions/subscript' +import { defineSuperscript } from 'prosekit/extensions/superscript' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineSubscript(), + defineSuperscript(), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ + : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, + type: 'subscript', + }), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ + : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, + type: 'superscript', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-sub-sup/src/components/editor/examples/sub-sup/index.ts b/svelte-sub-sup/src/components/editor/examples/sub-sup/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-sub-sup/src/components/editor/examples/sub-sup/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-sub-sup/src/components/editor/examples/sub-sup/toolbar.svelte b/svelte-sub-sup/src/components/editor/examples/sub-sup/toolbar.svelte new file mode 100644 index 0000000000..6ea215bc21 --- /dev/null +++ b/svelte-sub-sup/src/components/editor/examples/sub-sup/toolbar.svelte @@ -0,0 +1,42 @@ + + +
+ + +
diff --git a/svelte-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/svelte-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts new file mode 100644 index 0000000000..011be750dc --- /dev/null +++ b/svelte-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts @@ -0,0 +1,42 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'H', + }, + { + type: 'text', + marks: [ + { + type: 'subscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: 'O is water. x', + }, + { + type: 'text', + marks: [ + { + type: 'superscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: ' is a square.', + }, + ], + }, + ], +} diff --git a/svelte-sub-sup/src/components/editor/ui/button/button.svelte b/svelte-sub-sup/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-sub-sup/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-sub-sup/src/components/editor/ui/button/index.ts b/svelte-sub-sup/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-sub-sup/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-sub-sup/src/main.ts b/svelte-sub-sup/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-sub-sup/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-sub-sup/src/vite-env.d.ts b/svelte-sub-sup/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-sub-sup/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-sub-sup/svelte.config.js b/svelte-sub-sup/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-sub-sup/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-sub-sup/tsconfig.json b/svelte-sub-sup/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-sub-sup/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-sub-sup/tsconfig.node.json b/svelte-sub-sup/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-sub-sup/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-sub-sup/vite.config.ts b/svelte-sub-sup/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-sub-sup/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-table/.gitignore b/svelte-table/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-table/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-table/README.md b/svelte-table/README.md new file mode 100644 index 0000000000..160a9975ef --- /dev/null +++ b/svelte-table/README.md @@ -0,0 +1,15 @@ +# svelte-table + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-table) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-table) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-table svelte-table +cd svelte-table +npm install +npm run dev +``` diff --git a/svelte-table/index.html b/svelte-table/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-table/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-table/package.json b/svelte-table/package.json new file mode 100644 index 0000000000..657a17ea78 --- /dev/null +++ b/svelte-table/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-table", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-table/src/App.svelte b/svelte-table/src/App.svelte new file mode 100644 index 0000000000..e32b152299 --- /dev/null +++ b/svelte-table/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-table/src/app.css b/svelte-table/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-table/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-table/src/components/editor/examples/table/editor.svelte b/svelte-table/src/components/editor/examples/table/editor.svelte new file mode 100644 index 0000000000..26cf0c7885 --- /dev/null +++ b/svelte-table/src/components/editor/examples/table/editor.svelte @@ -0,0 +1,30 @@ + + + +
+
+
+ +
+
+
diff --git a/svelte-table/src/components/editor/examples/table/extension.ts b/svelte-table/src/components/editor/examples/table/extension.ts new file mode 100644 index 0000000000..ee7b142041 --- /dev/null +++ b/svelte-table/src/components/editor/examples/table/extension.ts @@ -0,0 +1,20 @@ +import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineTable(), + defineHistory(), + defineGapCursor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-table/src/components/editor/examples/table/index.ts b/svelte-table/src/components/editor/examples/table/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-table/src/components/editor/examples/table/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-table/src/components/editor/sample/sample-doc-table.ts b/svelte-table/src/components/editor/sample/sample-doc-table.ts new file mode 100644 index 0000000000..c737121672 --- /dev/null +++ b/svelte-table/src/components/editor/sample/sample-doc-table.ts @@ -0,0 +1,174 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D1', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D2', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], +} diff --git a/svelte-table/src/components/editor/ui/table-handle/index.ts b/svelte-table/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..308cef59de --- /dev/null +++ b/svelte-table/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle.svelte' diff --git a/svelte-table/src/components/editor/ui/table-handle/table-handle.svelte b/svelte-table/src/components/editor/ui/table-handle/table-handle.svelte new file mode 100644 index 0000000000..fc91f9a438 --- /dev/null +++ b/svelte-table/src/components/editor/ui/table-handle/table-handle.svelte @@ -0,0 +1,182 @@ + + + + + + + + + +
+
+ + + {#if $state.addTableColumnBefore.canExec} + + Insert Left + + {/if} + {#if $state.addTableColumnAfter.canExec} + + Insert Right + + {/if} + {#if $state.deleteCellSelection.canExec} + + Clear Contents + Del + + {/if} + {#if $state.deleteTableColumn.canExec} + + Delete Column + + {/if} + {#if $state.deleteTable.canExec} + + Delete Table + + {/if} + + +
+
+
+ + + + +
+
+ + + {#if $state.addTableRowAbove.canExec} + + Insert Above + + {/if} + {#if $state.addTableRowBelow.canExec} + + Insert Below + + {/if} + {#if $state.deleteCellSelection.canExec} + + Clear Contents + Del + + {/if} + {#if $state.deleteTableRow.canExec} + + Delete Row + + {/if} + {#if $state.deleteTable.canExec} + + Delete Table + + {/if} + + +
+
+
+
diff --git a/svelte-table/src/main.ts b/svelte-table/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-table/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-table/src/vite-env.d.ts b/svelte-table/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-table/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-table/svelte.config.js b/svelte-table/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-table/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-table/tsconfig.json b/svelte-table/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-table/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-table/tsconfig.node.json b/svelte-table/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-table/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-table/vite.config.ts b/svelte-table/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-table/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-text-align/.gitignore b/svelte-text-align/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-text-align/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-text-align/README.md b/svelte-text-align/README.md new file mode 100644 index 0000000000..39cfebd9d6 --- /dev/null +++ b/svelte-text-align/README.md @@ -0,0 +1,15 @@ +# svelte-text-align + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-text-align) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-text-align) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-text-align svelte-text-align +cd svelte-text-align +npm install +npm run dev +``` diff --git a/svelte-text-align/index.html b/svelte-text-align/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-text-align/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-text-align/package.json b/svelte-text-align/package.json new file mode 100644 index 0000000000..2babe2dc9e --- /dev/null +++ b/svelte-text-align/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-text-align", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-text-align/src/App.svelte b/svelte-text-align/src/App.svelte new file mode 100644 index 0000000000..d521e585a0 --- /dev/null +++ b/svelte-text-align/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-text-align/src/app.css b/svelte-text-align/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-text-align/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-text-align/src/components/editor/examples/text-align/editor.svelte b/svelte-text-align/src/components/editor/examples/text-align/editor.svelte new file mode 100644 index 0000000000..860777b581 --- /dev/null +++ b/svelte-text-align/src/components/editor/examples/text-align/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-text-align/src/components/editor/examples/text-align/extension.ts b/svelte-text-align/src/components/editor/examples/text-align/extension.ts new file mode 100644 index 0000000000..f1ae44dc7c --- /dev/null +++ b/svelte-text-align/src/components/editor/examples/text-align/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineTextAlign } from 'prosekit/extensions/text-align' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextAlign({ types: ['paragraph', 'heading'] }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-text-align/src/components/editor/examples/text-align/index.ts b/svelte-text-align/src/components/editor/examples/text-align/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-text-align/src/components/editor/examples/text-align/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-text-align/src/components/editor/examples/text-align/toolbar.svelte b/svelte-text-align/src/components/editor/examples/text-align/toolbar.svelte new file mode 100644 index 0000000000..b15ea499a9 --- /dev/null +++ b/svelte-text-align/src/components/editor/examples/text-align/toolbar.svelte @@ -0,0 +1,76 @@ + + +
+ + + + + + + +
diff --git a/svelte-text-align/src/components/editor/sample/sample-doc-text-align.ts b/svelte-text-align/src/components/editor/sample/sample-doc-text-align.ts new file mode 100644 index 0000000000..0724cea4f7 --- /dev/null +++ b/svelte-text-align/src/components/editor/sample/sample-doc-text-align.ts @@ -0,0 +1,56 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Heading', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'left', + }, + content: [ + { + type: 'text', + text: 'First paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Second paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'right', + }, + content: [ + { + type: 'text', + text: 'Third paragraph', + }, + ], + }, + ], +} diff --git a/svelte-text-align/src/components/editor/ui/button/button.svelte b/svelte-text-align/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-text-align/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-text-align/src/components/editor/ui/button/index.ts b/svelte-text-align/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-text-align/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-text-align/src/main.ts b/svelte-text-align/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-text-align/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-text-align/src/vite-env.d.ts b/svelte-text-align/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-text-align/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-text-align/svelte.config.js b/svelte-text-align/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-text-align/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-text-align/tsconfig.json b/svelte-text-align/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-text-align/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-text-align/tsconfig.node.json b/svelte-text-align/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-text-align/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-text-align/vite.config.ts b/svelte-text-align/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-text-align/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-text-color/.gitignore b/svelte-text-color/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-text-color/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-text-color/README.md b/svelte-text-color/README.md new file mode 100644 index 0000000000..ca7ea8911c --- /dev/null +++ b/svelte-text-color/README.md @@ -0,0 +1,15 @@ +# svelte-text-color + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-text-color) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-text-color) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-text-color svelte-text-color +cd svelte-text-color +npm install +npm run dev +``` diff --git a/svelte-text-color/index.html b/svelte-text-color/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-text-color/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-text-color/package.json b/svelte-text-color/package.json new file mode 100644 index 0000000000..81fc87b906 --- /dev/null +++ b/svelte-text-color/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-text-color", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-text-color/src/App.svelte b/svelte-text-color/src/App.svelte new file mode 100644 index 0000000000..420cbe9629 --- /dev/null +++ b/svelte-text-color/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-text-color/src/app.css b/svelte-text-color/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-text-color/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-text-color/src/components/editor/examples/text-color/editor.svelte b/svelte-text-color/src/components/editor/examples/text-color/editor.svelte new file mode 100644 index 0000000000..dbea1ffc04 --- /dev/null +++ b/svelte-text-color/src/components/editor/examples/text-color/editor.svelte @@ -0,0 +1,30 @@ + + + +
+
+
+ +
+
+
diff --git a/svelte-text-color/src/components/editor/examples/text-color/extension.ts b/svelte-text-color/src/components/editor/examples/text-color/extension.ts new file mode 100644 index 0000000000..d35d9d5c22 --- /dev/null +++ b/svelte-text-color/src/components/editor/examples/text-color/extension.ts @@ -0,0 +1,14 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineBackgroundColor } from 'prosekit/extensions/background-color' +import { defineTextColor } from 'prosekit/extensions/text-color' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextColor(), + defineBackgroundColor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-text-color/src/components/editor/examples/text-color/index.ts b/svelte-text-color/src/components/editor/examples/text-color/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-text-color/src/components/editor/examples/text-color/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-text-color/src/components/editor/examples/text-color/inline-menu.svelte b/svelte-text-color/src/components/editor/examples/text-color/inline-menu.svelte new file mode 100644 index 0000000000..7e2f79c8b0 --- /dev/null +++ b/svelte-text-color/src/components/editor/examples/text-color/inline-menu.svelte @@ -0,0 +1,127 @@ + + + open = event.detail} +> + + +
+
+
Text color
+
+ {#each $textColorState as color (color.label)} + + {/each} +
+
+
+
Background color
+
+ {#each $backgroundColorState as color (color.label)} + + {/each} +
+
+
+
+
+
diff --git a/svelte-text-color/src/components/editor/sample/sample-doc-text-color.ts b/svelte-text-color/src/components/editor/sample/sample-doc-text-color.ts new file mode 100644 index 0000000000..a4efe4308d --- /dev/null +++ b/svelte-text-color/src/components/editor/sample/sample-doc-text-color.ts @@ -0,0 +1,120 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#ef4444', + }, + }, + ], + text: 'Select', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#f97316', + }, + }, + ], + text: 'some', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#eab308', + }, + }, + ], + text: 'text', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#22c55e', + }, + }, + ], + text: 'to', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#3b82f6', + }, + }, + ], + text: 'change', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#6366f1', + }, + }, + ], + text: 'the', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#a855f7', + }, + }, + ], + text: 'color', + }, + ], + }, + ], +} diff --git a/svelte-text-color/src/components/editor/ui/button/button.svelte b/svelte-text-color/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-text-color/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-text-color/src/components/editor/ui/button/index.ts b/svelte-text-color/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-text-color/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-text-color/src/main.ts b/svelte-text-color/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-text-color/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-text-color/src/vite-env.d.ts b/svelte-text-color/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-text-color/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-text-color/svelte.config.js b/svelte-text-color/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-text-color/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-text-color/tsconfig.json b/svelte-text-color/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-text-color/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-text-color/tsconfig.node.json b/svelte-text-color/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-text-color/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-text-color/vite.config.ts b/svelte-text-color/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-text-color/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-toolbar/.gitignore b/svelte-toolbar/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-toolbar/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-toolbar/README.md b/svelte-toolbar/README.md new file mode 100644 index 0000000000..9213892f0c --- /dev/null +++ b/svelte-toolbar/README.md @@ -0,0 +1,15 @@ +# svelte-toolbar + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-toolbar) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-toolbar) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-toolbar svelte-toolbar +cd svelte-toolbar +npm install +npm run dev +``` diff --git a/svelte-toolbar/index.html b/svelte-toolbar/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-toolbar/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-toolbar/package.json b/svelte-toolbar/package.json new file mode 100644 index 0000000000..79bd3d8969 --- /dev/null +++ b/svelte-toolbar/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-toolbar", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-toolbar/src/App.svelte b/svelte-toolbar/src/App.svelte new file mode 100644 index 0000000000..fec082259a --- /dev/null +++ b/svelte-toolbar/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-toolbar/src/app.css b/svelte-toolbar/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-toolbar/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-toolbar/src/components/editor/examples/toolbar/editor.svelte b/svelte-toolbar/src/components/editor/examples/toolbar/editor.svelte new file mode 100644 index 0000000000..a637d4c3d3 --- /dev/null +++ b/svelte-toolbar/src/components/editor/examples/toolbar/editor.svelte @@ -0,0 +1,24 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-toolbar/src/components/editor/examples/toolbar/extension.ts b/svelte-toolbar/src/components/editor/examples/toolbar/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/svelte-toolbar/src/components/editor/examples/toolbar/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/svelte-toolbar/src/components/editor/examples/toolbar/index.ts b/svelte-toolbar/src/components/editor/examples/toolbar/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-toolbar/src/components/editor/examples/toolbar/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-toolbar/src/components/editor/sample/sample-uploader.ts b/svelte-toolbar/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/svelte-toolbar/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/svelte-toolbar/src/components/editor/ui/button/button.svelte b/svelte-toolbar/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-toolbar/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-toolbar/src/components/editor/ui/button/index.ts b/svelte-toolbar/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-toolbar/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/svelte-toolbar/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-toolbar/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-toolbar/src/components/editor/ui/toolbar/index.ts b/svelte-toolbar/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-toolbar/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-toolbar/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-toolbar/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-toolbar/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-toolbar/src/main.ts b/svelte-toolbar/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-toolbar/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-toolbar/src/vite-env.d.ts b/svelte-toolbar/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-toolbar/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-toolbar/svelte.config.js b/svelte-toolbar/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-toolbar/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-toolbar/tsconfig.json b/svelte-toolbar/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-toolbar/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-toolbar/tsconfig.node.json b/svelte-toolbar/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-toolbar/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-toolbar/vite.config.ts b/svelte-toolbar/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-toolbar/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-typography/.gitignore b/svelte-typography/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-typography/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-typography/README.md b/svelte-typography/README.md new file mode 100644 index 0000000000..569126dbd4 --- /dev/null +++ b/svelte-typography/README.md @@ -0,0 +1,15 @@ +# svelte-typography + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-typography) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-typography) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-typography svelte-typography +cd svelte-typography +npm install +npm run dev +``` diff --git a/svelte-typography/index.html b/svelte-typography/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-typography/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-typography/package.json b/svelte-typography/package.json new file mode 100644 index 0000000000..5a268ad1c0 --- /dev/null +++ b/svelte-typography/package.json @@ -0,0 +1,29 @@ +{ + "name": "example-svelte-typography", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-typography/src/App.svelte b/svelte-typography/src/App.svelte new file mode 100644 index 0000000000..2a693edc72 --- /dev/null +++ b/svelte-typography/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-typography/src/app.css b/svelte-typography/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-typography/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-typography/src/components/editor/examples/typography/editor.svelte b/svelte-typography/src/components/editor/examples/typography/editor.svelte new file mode 100644 index 0000000000..9bf6b8432f --- /dev/null +++ b/svelte-typography/src/components/editor/examples/typography/editor.svelte @@ -0,0 +1,32 @@ + + + +
+
+
+ + +
+
+
diff --git a/svelte-typography/src/components/editor/examples/typography/extension.ts b/svelte-typography/src/components/editor/examples/typography/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/svelte-typography/src/components/editor/examples/typography/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-typography/src/components/editor/examples/typography/index.ts b/svelte-typography/src/components/editor/examples/typography/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-typography/src/components/editor/examples/typography/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-typography/src/components/editor/sample/katex.ts b/svelte-typography/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/svelte-typography/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/svelte-typography/src/components/editor/sample/sample-doc-typography.ts b/svelte-typography/src/components/editor/sample/sample-doc-typography.ts new file mode 100644 index 0000000000..db18b8155c --- /dev/null +++ b/svelte-typography/src/components/editor/sample/sample-doc-typography.ts @@ -0,0 +1,693 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'ProseKit Typography', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This example shows the typography styles provided by ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'prosekit/basic/typography.css', + }, + { + type: 'text', + text: '.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Inline marks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Text can be formatted in different ways: ', + }, + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'bold text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'italic text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'underlined text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'strikethrough text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'inline code', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://example.com', + target: null, + rel: null, + }, + }, + ], + text: 'links', + }, + { + type: 'text', + text: ',', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'and hard breaks (Shift+Enter).', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Headings', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Heading 1', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Heading 2', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Heading 3', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 4, + }, + content: [ + { + type: 'text', + text: 'Heading 4', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 5, + }, + content: [ + { + type: 'text', + text: 'Heading 5', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 6, + }, + content: [ + { + type: 'text', + text: 'Heading 6', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Lists', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here are different types of lists:', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 1', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 2', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item A', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item B', + }, + ], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'First ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Second ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: true, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Completed task', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Pending task', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Blockquotes', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: '', + }, + content: [ + { + type: 'text', + text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Horizontal Rule', + }, + ], + }, + { + type: 'horizontalRule', + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blurred/640x360/42', + }, + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Tables', + }, + ], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 1', + }, + ], + }, + ], + }, + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 3', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 4', + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Math', + }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Inline math like Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text.' }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Block-level equations are displayed on their own line:', + }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + ], +} diff --git a/svelte-typography/src/components/editor/ui/block-handle/block-handle.svelte b/svelte-typography/src/components/editor/ui/block-handle/block-handle.svelte new file mode 100644 index 0000000000..f67e42dc91 --- /dev/null +++ b/svelte-typography/src/components/editor/ui/block-handle/block-handle.svelte @@ -0,0 +1,28 @@ + + + + + + +
+
+ +
+
+
+
+
diff --git a/svelte-typography/src/components/editor/ui/block-handle/index.ts b/svelte-typography/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..6d21191384 --- /dev/null +++ b/svelte-typography/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.svelte' diff --git a/svelte-typography/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/svelte-typography/src/components/editor/ui/drop-indicator/drop-indicator.svelte new file mode 100644 index 0000000000..7f6cac1db0 --- /dev/null +++ b/svelte-typography/src/components/editor/ui/drop-indicator/drop-indicator.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-typography/src/components/editor/ui/drop-indicator/index.ts b/svelte-typography/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..06e89357ed --- /dev/null +++ b/svelte-typography/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator.svelte' diff --git a/svelte-typography/src/main.ts b/svelte-typography/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-typography/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-typography/src/vite-env.d.ts b/svelte-typography/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-typography/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-typography/svelte.config.js b/svelte-typography/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-typography/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-typography/tsconfig.json b/svelte-typography/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-typography/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-typography/tsconfig.node.json b/svelte-typography/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-typography/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-typography/vite.config.ts b/svelte-typography/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-typography/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-underline/.gitignore b/svelte-underline/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-underline/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-underline/README.md b/svelte-underline/README.md new file mode 100644 index 0000000000..3e08a9ca7a --- /dev/null +++ b/svelte-underline/README.md @@ -0,0 +1,15 @@ +# svelte-underline + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-underline) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-underline) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-underline svelte-underline +cd svelte-underline +npm install +npm run dev +``` diff --git a/svelte-underline/index.html b/svelte-underline/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-underline/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-underline/package.json b/svelte-underline/package.json new file mode 100644 index 0000000000..bfc6b78805 --- /dev/null +++ b/svelte-underline/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-underline", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-underline/src/App.svelte b/svelte-underline/src/App.svelte new file mode 100644 index 0000000000..93deae80ee --- /dev/null +++ b/svelte-underline/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-underline/src/app.css b/svelte-underline/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-underline/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-underline/src/components/editor/examples/underline/editor.svelte b/svelte-underline/src/components/editor/examples/underline/editor.svelte new file mode 100644 index 0000000000..b005c3ee6b --- /dev/null +++ b/svelte-underline/src/components/editor/examples/underline/editor.svelte @@ -0,0 +1,30 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-underline/src/components/editor/examples/underline/extension.ts b/svelte-underline/src/components/editor/examples/underline/extension.ts new file mode 100644 index 0000000000..16a9b58284 --- /dev/null +++ b/svelte-underline/src/components/editor/examples/underline/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineUnderline(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-underline/src/components/editor/examples/underline/index.ts b/svelte-underline/src/components/editor/examples/underline/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-underline/src/components/editor/examples/underline/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-underline/src/components/editor/sample/sample-doc-underline.ts b/svelte-underline/src/components/editor/sample/sample-doc-underline.ts new file mode 100644 index 0000000000..6af561064b --- /dev/null +++ b/svelte-underline/src/components/editor/sample/sample-doc-underline.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'This is underline', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/svelte-underline/src/components/editor/ui/button/button.svelte b/svelte-underline/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-underline/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-underline/src/components/editor/ui/button/index.ts b/svelte-underline/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-underline/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-underline/src/components/editor/ui/image-upload-popover/index.ts b/svelte-underline/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-underline/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-underline/src/components/editor/ui/toolbar/index.ts b/svelte-underline/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-underline/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-underline/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-underline/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-underline/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-underline/src/main.ts b/svelte-underline/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-underline/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-underline/src/vite-env.d.ts b/svelte-underline/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-underline/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-underline/svelte.config.js b/svelte-underline/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-underline/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-underline/tsconfig.json b/svelte-underline/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-underline/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-underline/tsconfig.node.json b/svelte-underline/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-underline/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-underline/vite.config.ts b/svelte-underline/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-underline/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-unmount/.gitignore b/svelte-unmount/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-unmount/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-unmount/README.md b/svelte-unmount/README.md new file mode 100644 index 0000000000..d0809e179b --- /dev/null +++ b/svelte-unmount/README.md @@ -0,0 +1,15 @@ +# svelte-unmount + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-unmount) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-unmount) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-unmount svelte-unmount +cd svelte-unmount +npm install +npm run dev +``` diff --git a/svelte-unmount/index.html b/svelte-unmount/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-unmount/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-unmount/package.json b/svelte-unmount/package.json new file mode 100644 index 0000000000..d29de2d2df --- /dev/null +++ b/svelte-unmount/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-unmount", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-unmount/src/App.svelte b/svelte-unmount/src/App.svelte new file mode 100644 index 0000000000..8fb35fbcfe --- /dev/null +++ b/svelte-unmount/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-unmount/src/app.css b/svelte-unmount/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-unmount/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-unmount/src/components/editor/examples/unmount/editor-component.svelte b/svelte-unmount/src/components/editor/examples/unmount/editor-component.svelte new file mode 100644 index 0000000000..1096263f08 --- /dev/null +++ b/svelte-unmount/src/components/editor/examples/unmount/editor-component.svelte @@ -0,0 +1,28 @@ + + + +
+
+
+ +
+
+ +
diff --git a/svelte-unmount/src/components/editor/examples/unmount/editor.svelte b/svelte-unmount/src/components/editor/examples/unmount/editor.svelte new file mode 100644 index 0000000000..17ed0a26fa --- /dev/null +++ b/svelte-unmount/src/components/editor/examples/unmount/editor.svelte @@ -0,0 +1,37 @@ + + +
+
+ + {#each editorKeys as key (key)} + + {/each} +
+ {#each editorKeys as key (key)} +
+ +
+ {/each} +
diff --git a/svelte-unmount/src/components/editor/examples/unmount/extension-component.svelte b/svelte-unmount/src/components/editor/examples/unmount/extension-component.svelte new file mode 100644 index 0000000000..eaf6f0d953 --- /dev/null +++ b/svelte-unmount/src/components/editor/examples/unmount/extension-component.svelte @@ -0,0 +1,13 @@ + diff --git a/svelte-unmount/src/components/editor/examples/unmount/index.ts b/svelte-unmount/src/components/editor/examples/unmount/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-unmount/src/components/editor/examples/unmount/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-unmount/src/components/editor/ui/button/button.svelte b/svelte-unmount/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-unmount/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-unmount/src/components/editor/ui/button/index.ts b/svelte-unmount/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-unmount/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-unmount/src/components/editor/ui/inline-menu/index.ts b/svelte-unmount/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..bf78dd2139 --- /dev/null +++ b/svelte-unmount/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.svelte' diff --git a/svelte-unmount/src/components/editor/ui/inline-menu/inline-menu.svelte b/svelte-unmount/src/components/editor/ui/inline-menu/inline-menu.svelte new file mode 100644 index 0000000000..989f0c013b --- /dev/null +++ b/svelte-unmount/src/components/editor/ui/inline-menu/inline-menu.svelte @@ -0,0 +1,207 @@ + + + { + if (!event.detail) linkMenuOpen = false + }} +> + + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.link?.canExec && $items.link} + + {/if} + + + + + { + linkMenuOpen = event.detail + }} +> + + + {#if linkMenuOpen && $items.link} +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ {/if} + {#if $items.link?.isActive} + + {/if} +
+
+
diff --git a/svelte-unmount/src/main.ts b/svelte-unmount/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-unmount/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-unmount/src/vite-env.d.ts b/svelte-unmount/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-unmount/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-unmount/svelte.config.js b/svelte-unmount/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-unmount/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-unmount/tsconfig.json b/svelte-unmount/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-unmount/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-unmount/tsconfig.node.json b/svelte-unmount/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-unmount/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-unmount/vite.config.ts b/svelte-unmount/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-unmount/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-user-menu-dynamic/.gitignore b/svelte-user-menu-dynamic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-user-menu-dynamic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-user-menu-dynamic/README.md b/svelte-user-menu-dynamic/README.md new file mode 100644 index 0000000000..6d55f1a102 --- /dev/null +++ b/svelte-user-menu-dynamic/README.md @@ -0,0 +1,15 @@ +# svelte-user-menu-dynamic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-user-menu-dynamic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-user-menu-dynamic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-user-menu-dynamic svelte-user-menu-dynamic +cd svelte-user-menu-dynamic +npm install +npm run dev +``` diff --git a/svelte-user-menu-dynamic/index.html b/svelte-user-menu-dynamic/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-user-menu-dynamic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-user-menu-dynamic/package.json b/svelte-user-menu-dynamic/package.json new file mode 100644 index 0000000000..a039119d3a --- /dev/null +++ b/svelte-user-menu-dynamic/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-user-menu-dynamic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-user-menu-dynamic/src/App.svelte b/svelte-user-menu-dynamic/src/App.svelte new file mode 100644 index 0000000000..a0c9a2f997 --- /dev/null +++ b/svelte-user-menu-dynamic/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-user-menu-dynamic/src/app.css b/svelte-user-menu-dynamic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-user-menu-dynamic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.svelte b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.svelte new file mode 100644 index 0000000000..0d6b8a0ec0 --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.svelte @@ -0,0 +1,22 @@ + + + +
+
+
+ +
+
+
diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts new file mode 100644 index 0000000000..ff2c40b104 --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.svelte.ts b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.svelte.ts new file mode 100644 index 0000000000..1fba95e9e0 --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.svelte.ts @@ -0,0 +1,37 @@ +import { queryUsers, type User } from '../../sample/sample-query-users' + +export function useUserQuery( + getQuery: () => string, + getEnabled: () => boolean, +) { + let loading = $state(true) + let users = $state([]) + + $effect(() => { + const query = getQuery() + const enabled = getEnabled() + + if (!enabled) { + users = [] + return + } + + loading = true + let cancelled = false + void queryUsers(query).then((result) => { + if (cancelled) { + return + } + users = result + loading = false + }) + return () => { + cancelled = true + } + }) + + return { + getLoading: () => loading, + getUsers: () => users, + } +} diff --git a/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.svelte b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.svelte new file mode 100644 index 0000000000..831ea21723 --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.svelte @@ -0,0 +1,25 @@ + + + diff --git a/svelte-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/svelte-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts new file mode 100644 index 0000000000..ab78fd5525 --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts @@ -0,0 +1,40 @@ +import { users } from './sample-user-data' + +export interface User { + id: number + name: string +} + +const connectHandlers: VoidFunction[] = [] +let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' + +/** + * A utility function to simulate different network states. Useful for testing. + * + * @internal + */ +export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { + networkStatus = status + if (status !== 'offline') { + connectHandlers.forEach((handler) => handler()) + connectHandlers.length = 0 + } +} + +/** + * Simulate a user searching with some delay. + */ +export async function queryUsers(query: string): Promise { + if (networkStatus === 'offline') { + await new Promise((resolve) => connectHandlers.push(resolve)) + } + if (networkStatus === 'slow') { + await new Promise((resolve) => setTimeout(resolve, 300)) + } + + const normalizedQuery = query.toLowerCase().trim() + const filteredUsers = users + .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) + .slice(0, 10) + return filteredUsers +} diff --git a/svelte-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/svelte-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..7dbbd80d0e --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu.svelte' diff --git a/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.svelte b/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.svelte new file mode 100644 index 0000000000..5c0475d87e --- /dev/null +++ b/svelte-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.svelte @@ -0,0 +1,70 @@ + + + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} +> + + +
+ + {loading ? 'Loading...' : 'No results'} + + + {#each props.users as user (user.id)} + handleUserInsert(user.id, user.name)} + > + {#if loading} + + {user.name} + + {:else} + + {user.name} + + {/if} + + {/each} +
+
+
+
diff --git a/svelte-user-menu-dynamic/src/main.ts b/svelte-user-menu-dynamic/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-user-menu-dynamic/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-user-menu-dynamic/src/vite-env.d.ts b/svelte-user-menu-dynamic/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-user-menu-dynamic/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-user-menu-dynamic/svelte.config.js b/svelte-user-menu-dynamic/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-user-menu-dynamic/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-user-menu-dynamic/tsconfig.json b/svelte-user-menu-dynamic/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-user-menu-dynamic/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-user-menu-dynamic/tsconfig.node.json b/svelte-user-menu-dynamic/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-user-menu-dynamic/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-user-menu-dynamic/vite.config.ts b/svelte-user-menu-dynamic/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-user-menu-dynamic/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-user-menu/.gitignore b/svelte-user-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-user-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-user-menu/README.md b/svelte-user-menu/README.md new file mode 100644 index 0000000000..91b1d7f782 --- /dev/null +++ b/svelte-user-menu/README.md @@ -0,0 +1,15 @@ +# svelte-user-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-user-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-user-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-user-menu svelte-user-menu +cd svelte-user-menu +npm install +npm run dev +``` diff --git a/svelte-user-menu/index.html b/svelte-user-menu/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-user-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-user-menu/package.json b/svelte-user-menu/package.json new file mode 100644 index 0000000000..9c80e624de --- /dev/null +++ b/svelte-user-menu/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-user-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-user-menu/src/App.svelte b/svelte-user-menu/src/App.svelte new file mode 100644 index 0000000000..4ff7b9d541 --- /dev/null +++ b/svelte-user-menu/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-user-menu/src/app.css b/svelte-user-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-user-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-user-menu/src/components/editor/examples/user-menu/editor.svelte b/svelte-user-menu/src/components/editor/examples/user-menu/editor.svelte new file mode 100644 index 0000000000..701352a92e --- /dev/null +++ b/svelte-user-menu/src/components/editor/examples/user-menu/editor.svelte @@ -0,0 +1,27 @@ + + + +
+
+
+ + +
+
+
diff --git a/svelte-user-menu/src/components/editor/examples/user-menu/extension.ts b/svelte-user-menu/src/components/editor/examples/user-menu/extension.ts new file mode 100644 index 0000000000..56a97a4779 --- /dev/null +++ b/svelte-user-menu/src/components/editor/examples/user-menu/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone or # to tag something...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-user-menu/src/components/editor/examples/user-menu/index.ts b/svelte-user-menu/src/components/editor/examples/user-menu/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-user-menu/src/components/editor/examples/user-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-user-menu/src/components/editor/sample/sample-tag-data.ts b/svelte-user-menu/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/svelte-user-menu/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/svelte-user-menu/src/components/editor/sample/sample-user-data.ts b/svelte-user-menu/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/svelte-user-menu/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/svelte-user-menu/src/components/editor/ui/tag-menu/index.ts b/svelte-user-menu/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..0884d7f5a1 --- /dev/null +++ b/svelte-user-menu/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu.svelte' diff --git a/svelte-user-menu/src/components/editor/ui/tag-menu/tag-menu.svelte b/svelte-user-menu/src/components/editor/ui/tag-menu/tag-menu.svelte new file mode 100644 index 0000000000..8b9bf23f30 --- /dev/null +++ b/svelte-user-menu/src/components/editor/ui/tag-menu/tag-menu.svelte @@ -0,0 +1,53 @@ + + + + + +
+ + No results + + + {#each props.tags as tag (tag.id)} + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + {/each} +
+
+
+
diff --git a/svelte-user-menu/src/components/editor/ui/user-menu/index.ts b/svelte-user-menu/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..7dbbd80d0e --- /dev/null +++ b/svelte-user-menu/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu.svelte' diff --git a/svelte-user-menu/src/components/editor/ui/user-menu/user-menu.svelte b/svelte-user-menu/src/components/editor/ui/user-menu/user-menu.svelte new file mode 100644 index 0000000000..5c0475d87e --- /dev/null +++ b/svelte-user-menu/src/components/editor/ui/user-menu/user-menu.svelte @@ -0,0 +1,70 @@ + + + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} +> + + +
+ + {loading ? 'Loading...' : 'No results'} + + + {#each props.users as user (user.id)} + handleUserInsert(user.id, user.name)} + > + {#if loading} + + {user.name} + + {:else} + + {user.name} + + {/if} + + {/each} +
+
+
+
diff --git a/svelte-user-menu/src/main.ts b/svelte-user-menu/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-user-menu/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-user-menu/src/vite-env.d.ts b/svelte-user-menu/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-user-menu/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-user-menu/svelte.config.js b/svelte-user-menu/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-user-menu/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-user-menu/tsconfig.json b/svelte-user-menu/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-user-menu/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-user-menu/tsconfig.node.json b/svelte-user-menu/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-user-menu/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-user-menu/vite.config.ts b/svelte-user-menu/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-user-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-word-counter/.gitignore b/svelte-word-counter/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-word-counter/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-word-counter/README.md b/svelte-word-counter/README.md new file mode 100644 index 0000000000..ee700b30fa --- /dev/null +++ b/svelte-word-counter/README.md @@ -0,0 +1,15 @@ +# svelte-word-counter + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-word-counter) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-word-counter) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-word-counter svelte-word-counter +cd svelte-word-counter +npm install +npm run dev +``` diff --git a/svelte-word-counter/index.html b/svelte-word-counter/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-word-counter/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-word-counter/package.json b/svelte-word-counter/package.json new file mode 100644 index 0000000000..63f672d51b --- /dev/null +++ b/svelte-word-counter/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-svelte-word-counter", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-word-counter/src/App.svelte b/svelte-word-counter/src/App.svelte new file mode 100644 index 0000000000..592f106186 --- /dev/null +++ b/svelte-word-counter/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-word-counter/src/app.css b/svelte-word-counter/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-word-counter/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-word-counter/src/components/editor/examples/word-counter/editor.svelte b/svelte-word-counter/src/components/editor/examples/word-counter/editor.svelte new file mode 100644 index 0000000000..dd19aee366 --- /dev/null +++ b/svelte-word-counter/src/components/editor/examples/word-counter/editor.svelte @@ -0,0 +1,30 @@ + + + +
+
+
+ +
+
+
diff --git a/svelte-word-counter/src/components/editor/examples/word-counter/extension.ts b/svelte-word-counter/src/components/editor/examples/word-counter/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/svelte-word-counter/src/components/editor/examples/word-counter/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/svelte-word-counter/src/components/editor/examples/word-counter/index.ts b/svelte-word-counter/src/components/editor/examples/word-counter/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-word-counter/src/components/editor/examples/word-counter/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/svelte-word-counter/src/components/editor/sample/sample-doc-word-counter.ts new file mode 100644 index 0000000000..0b5d435038 --- /dev/null +++ b/svelte-word-counter/src/components/editor/sample/sample-doc-word-counter.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Start typing and observe the word count update below.', + }, + ], + }, + ], +} diff --git a/svelte-word-counter/src/components/editor/ui/word-counter/index.ts b/svelte-word-counter/src/components/editor/ui/word-counter/index.ts new file mode 100644 index 0000000000..e0c531aedf --- /dev/null +++ b/svelte-word-counter/src/components/editor/ui/word-counter/index.ts @@ -0,0 +1 @@ +export { default as WordCounter } from './word-counter.svelte' diff --git a/svelte-word-counter/src/components/editor/ui/word-counter/word-counter.svelte b/svelte-word-counter/src/components/editor/ui/word-counter/word-counter.svelte new file mode 100644 index 0000000000..72c4cc2cc5 --- /dev/null +++ b/svelte-word-counter/src/components/editor/ui/word-counter/word-counter.svelte @@ -0,0 +1,20 @@ + + +
+ Word Count: {$counts.wordCount} +
+ Character Count: {$counts.characterCount} +
diff --git a/svelte-word-counter/src/main.ts b/svelte-word-counter/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-word-counter/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-word-counter/src/vite-env.d.ts b/svelte-word-counter/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-word-counter/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-word-counter/svelte.config.js b/svelte-word-counter/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-word-counter/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-word-counter/tsconfig.json b/svelte-word-counter/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-word-counter/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-word-counter/tsconfig.node.json b/svelte-word-counter/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-word-counter/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-word-counter/vite.config.ts b/svelte-word-counter/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-word-counter/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/svelte-yjs/.gitignore b/svelte-yjs/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/svelte-yjs/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/svelte-yjs/README.md b/svelte-yjs/README.md new file mode 100644 index 0000000000..44823f7136 --- /dev/null +++ b/svelte-yjs/README.md @@ -0,0 +1,15 @@ +# svelte-yjs + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/svelte-yjs) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/svelte-yjs) + +Run the example locally with: + +```bash +npx degit prosekit/examples/svelte-yjs svelte-yjs +cd svelte-yjs +npm install +npm run dev +``` diff --git a/svelte-yjs/index.html b/svelte-yjs/index.html new file mode 100644 index 0000000000..58212c2501 --- /dev/null +++ b/svelte-yjs/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Svelte + + +
+ + + diff --git a/svelte-yjs/package.json b/svelte-yjs/package.json new file mode 100644 index 0000000000..7d91c55513 --- /dev/null +++ b/svelte-yjs/package.json @@ -0,0 +1,31 @@ +{ + "name": "example-svelte-yjs", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-check --tsconfig ./tsconfig.json && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "y-prosemirror": "^1.3.7", + "y-websocket": "^3.0.0", + "yjs": "^13.6.30" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "@tsconfig/svelte": "^5.0.8", + "postcss": "^8.5.14", + "svelte": "5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "tslib": "^2.8.1", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/svelte-yjs/src/App.svelte b/svelte-yjs/src/App.svelte new file mode 100644 index 0000000000..4a469f04e6 --- /dev/null +++ b/svelte-yjs/src/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/svelte-yjs/src/app.css b/svelte-yjs/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/svelte-yjs/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/svelte-yjs/src/components/editor/examples/yjs/editor-component.svelte b/svelte-yjs/src/components/editor/examples/yjs/editor-component.svelte new file mode 100644 index 0000000000..3ac3d77918 --- /dev/null +++ b/svelte-yjs/src/components/editor/examples/yjs/editor-component.svelte @@ -0,0 +1,33 @@ + + + +
+ +
+
+
+
+
diff --git a/svelte-yjs/src/components/editor/examples/yjs/editor.svelte b/svelte-yjs/src/components/editor/examples/yjs/editor.svelte new file mode 100644 index 0000000000..7faf8286e1 --- /dev/null +++ b/svelte-yjs/src/components/editor/examples/yjs/editor.svelte @@ -0,0 +1,27 @@ + + +
+ + +
diff --git a/svelte-yjs/src/components/editor/examples/yjs/extension.ts b/svelte-yjs/src/components/editor/examples/yjs/extension.ts new file mode 100644 index 0000000000..b2546b126e --- /dev/null +++ b/svelte-yjs/src/components/editor/examples/yjs/extension.ts @@ -0,0 +1,48 @@ +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' +import { defineYjs } from 'prosekit/extensions/yjs' +import type { Awareness } from 'prosekit/extensions/yjs' +import type * as Y from 'yjs' + +export function defineExtension(doc: Y.Doc, awareness: Awareness) { + return union( + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineYjs({ doc, awareness }), + ) +} + +export type EditorExtension = ReturnType diff --git a/svelte-yjs/src/components/editor/examples/yjs/index.ts b/svelte-yjs/src/components/editor/examples/yjs/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/svelte-yjs/src/components/editor/examples/yjs/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/svelte-yjs/src/components/editor/ui/button/button.svelte b/svelte-yjs/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/svelte-yjs/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/svelte-yjs/src/components/editor/ui/button/index.ts b/svelte-yjs/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/svelte-yjs/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/svelte-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/svelte-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte new file mode 100644 index 0000000000..c80af45721 --- /dev/null +++ b/svelte-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte @@ -0,0 +1,121 @@ + + + + + + + + + {#if !file} + + + {/if} + + {#if !url} + + + {/if} + + {#if url} + + {/if} + + {#if file} + + {/if} + + diff --git a/svelte-yjs/src/components/editor/ui/image-upload-popover/index.ts b/svelte-yjs/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..e53e71c348 --- /dev/null +++ b/svelte-yjs/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.svelte' diff --git a/svelte-yjs/src/components/editor/ui/toolbar/index.ts b/svelte-yjs/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/svelte-yjs/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/svelte-yjs/src/components/editor/ui/toolbar/toolbar.svelte b/svelte-yjs/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/svelte-yjs/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/svelte-yjs/src/main.ts b/svelte-yjs/src/main.ts new file mode 100644 index 0000000000..b4bc565380 --- /dev/null +++ b/svelte-yjs/src/main.ts @@ -0,0 +1,8 @@ +import './app.css' + +import { mount } from 'svelte' +import App from './App.svelte' + +const app = mount(App, { target: document.getElementById('app')! }) + +export default app diff --git a/svelte-yjs/src/vite-env.d.ts b/svelte-yjs/src/vite-env.d.ts new file mode 100644 index 0000000000..4078e7476a --- /dev/null +++ b/svelte-yjs/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/svelte-yjs/svelte.config.js b/svelte-yjs/svelte.config.js new file mode 100644 index 0000000000..b0683fd24d --- /dev/null +++ b/svelte-yjs/svelte.config.js @@ -0,0 +1,7 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + // Consult https://svelte.dev/docs#compile-time-svelte-preprocess + // for more information about preprocessors + preprocess: vitePreprocess(), +} diff --git a/svelte-yjs/tsconfig.json b/svelte-yjs/tsconfig.json new file mode 100644 index 0000000000..86876593dd --- /dev/null +++ b/svelte-yjs/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@tsconfig/svelte/tsconfig.json", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "resolveJsonModule": true, + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable checkJs if you'd like to use dynamic types in JS. + * Note that setting allowJs false does not prevent the use + * of JS in `.svelte` files. + */ + "allowJs": true, + "checkJs": true, + "allowImportingTsExtensions": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/svelte-yjs/tsconfig.node.json b/svelte-yjs/tsconfig.node.json new file mode 100644 index 0000000000..494bfe0835 --- /dev/null +++ b/svelte-yjs/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler" + }, + "include": ["vite.config.ts"] +} diff --git a/svelte-yjs/vite.config.ts b/svelte-yjs/vite.config.ts new file mode 100644 index 0000000000..11edea7f23 --- /dev/null +++ b/svelte-yjs/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import { svelte } from '@sveltejs/vite-plugin-svelte' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte(), tailwindcss()], +}) diff --git a/sveltekit-full/.gitignore b/sveltekit-full/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/sveltekit-full/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/sveltekit-full/README.md b/sveltekit-full/README.md new file mode 100644 index 0000000000..d335fd4f33 --- /dev/null +++ b/sveltekit-full/README.md @@ -0,0 +1,15 @@ +# sveltekit-full + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/sveltekit-full) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/sveltekit-full) + +Run the example locally with: + +```bash +npx degit prosekit/examples/sveltekit-full sveltekit-full +cd sveltekit-full +npm install +npm run dev +``` diff --git a/sveltekit-full/package.json b/sveltekit-full/package.json new file mode 100644 index 0000000000..c52d414850 --- /dev/null +++ b/sveltekit-full/package.json @@ -0,0 +1,31 @@ +{ + "name": "example-sveltekit-full", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "build": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json && vite build", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "dev": "vite dev", + "prepare": "svelte-kit sync || echo ''", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@sveltejs/adapter-auto": "^7.0.1", + "@sveltejs/kit": "^2.60.1", + "@sveltejs/vite-plugin-svelte": "^7.1.2", + "@tailwindcss/vite": "^4.3.0", + "svelte": "^5.55.7", + "svelte-check": "^4.4.8", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13" + } +} diff --git a/sveltekit-full/src/app.css b/sveltekit-full/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/sveltekit-full/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/sveltekit-full/src/app.d.ts b/sveltekit-full/src/app.d.ts new file mode 100644 index 0000000000..367926a580 --- /dev/null +++ b/sveltekit-full/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {} diff --git a/sveltekit-full/src/app.html b/sveltekit-full/src/app.html new file mode 100644 index 0000000000..84ffad1665 --- /dev/null +++ b/sveltekit-full/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/sveltekit-full/src/components/editor/examples/full/editor.svelte b/sveltekit-full/src/components/editor/examples/full/editor.svelte new file mode 100644 index 0000000000..09f3d7d9d3 --- /dev/null +++ b/sveltekit-full/src/components/editor/examples/full/editor.svelte @@ -0,0 +1,47 @@ + + + +
+ +
+
+ + + + + + + +
+
+
diff --git a/sveltekit-full/src/components/editor/examples/full/extension.ts b/sveltekit-full/src/components/editor/examples/full/extension.ts new file mode 100644 index 0000000000..5fc2f60685 --- /dev/null +++ b/sveltekit-full/src/components/editor/examples/full/extension.ts @@ -0,0 +1,34 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineImageUploadHandler } from 'prosekit/extensions/image' +import { defineMath } from 'prosekit/extensions/math' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' +import { sampleUploader } from '../../sample/sample-uploader' +import { defineCodeBlockView } from '../../ui/code-block-view' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + defineMention(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + defineCodeBlockShiki(), + defineHorizontalRule(), + defineCodeBlockView(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/sveltekit-full/src/components/editor/examples/full/index.ts b/sveltekit-full/src/components/editor/examples/full/index.ts new file mode 100644 index 0000000000..1933e61970 --- /dev/null +++ b/sveltekit-full/src/components/editor/examples/full/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.svelte' diff --git a/sveltekit-full/src/components/editor/sample/katex.ts b/sveltekit-full/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/sveltekit-full/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/sveltekit-full/src/components/editor/sample/sample-doc-full.ts b/sveltekit-full/src/components/editor/sample/sample-doc-full.ts new file mode 100644 index 0000000000..13e49b634d --- /dev/null +++ b/sveltekit-full/src/components/editor/sample/sample-doc-full.ts @@ -0,0 +1,442 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'The editor that thinks like you' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', + }, + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'writing without barriers', + }, + { type: 'text', text: '.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Text that shines.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Make your words ' }, + { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, + { type: 'text', text: ', or ' }, + { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, + { type: 'text', text: '. Add ' }, + { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, + { type: 'text', text: ' that stands out. Create ' }, + { + type: 'text', + marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], + text: 'links', + }, + { type: 'text', text: ' that connect.' }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Select any text to format it. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '@' }, + { type: 'text', text: ' to mention ' }, + { + type: 'mention', + attrs: { id: '39', value: '@someone', kind: 'user' }, + }, + { type: 'text', text: ' or ' }, + { type: 'text', marks: [{ type: 'code' }], text: '#' }, + { type: 'text', text: ' for ' }, + { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, + { type: 'text', text: '. Press ' }, + { type: 'text', marks: [{ type: 'code' }], text: '/' }, + { type: 'text', text: " and discover what's possible." }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Lists that organize.' }], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Bullet points that guide thoughts' }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Nested lists for complex ideas' }], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sub-points flow naturally' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Tasks that focus' }], + }, + { + type: 'list', + attrs: { kind: 'task', order: null, checked: true, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Done feels good' }], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Todo drives action' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Numbered steps' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sequential thinking' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Clear progress' }], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Code that inspires.' }], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Images that captivate.' }], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/season/320x240/107', + }, + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the handle in the bottom right corner to resize.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Tables that structure.' }], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'Feature', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'How to use', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Format text' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Select and choose' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Perfect styling' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Add mentions' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Type @ and name' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Connected ideas' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Insert anything' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Press / for menu' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Endless possibilities' }], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Math that renders.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Inline math like ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' appears within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Quotes that inspire.' }], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: '"This is not just an editor. This is how writing should feel."', + }, + ], + }, + ], + }, + { type: 'horizontalRule' }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Start typing. Everything else just flows.' }, + ], + }, + ], +} diff --git a/sveltekit-full/src/components/editor/sample/sample-tag-data.ts b/sveltekit-full/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/sveltekit-full/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/sveltekit-full/src/components/editor/sample/sample-uploader.ts b/sveltekit-full/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/sveltekit-full/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/sveltekit-full/src/components/editor/sample/sample-user-data.ts b/sveltekit-full/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/sveltekit-full/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/sveltekit-full/src/components/editor/ui/block-handle/block-handle.svelte b/sveltekit-full/src/components/editor/ui/block-handle/block-handle.svelte new file mode 100644 index 0000000000..f67e42dc91 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/block-handle/block-handle.svelte @@ -0,0 +1,28 @@ + + + + + + +
+
+ +
+
+
+
+
diff --git a/sveltekit-full/src/components/editor/ui/block-handle/index.ts b/sveltekit-full/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..6d21191384 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.svelte' diff --git a/sveltekit-full/src/components/editor/ui/button/button.svelte b/sveltekit-full/src/components/editor/ui/button/button.svelte new file mode 100644 index 0000000000..43680d3bf0 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/button/button.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if props.tooltip} + + + {props.tooltip} + + + {/if} + diff --git a/sveltekit-full/src/components/editor/ui/button/index.ts b/sveltekit-full/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..1d087605a7 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.svelte' diff --git a/sveltekit-full/src/components/editor/ui/code-block-view/code-block-view.svelte b/sveltekit-full/src/components/editor/ui/code-block-view/code-block-view.svelte new file mode 100644 index 0000000000..aaa4617fc1 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/code-block-view/code-block-view.svelte @@ -0,0 +1,40 @@ + + + +

diff --git a/sveltekit-full/src/components/editor/ui/code-block-view/index.ts b/sveltekit-full/src/components/editor/ui/code-block-view/index.ts
new file mode 100644
index 0000000000..eb54b2f6d9
--- /dev/null
+++ b/sveltekit-full/src/components/editor/ui/code-block-view/index.ts
@@ -0,0 +1,15 @@
+import type { Extension } from 'prosekit/core'
+import {
+  defineSvelteNodeView,
+  type SvelteNodeViewComponent,
+} from 'prosekit/svelte'
+
+import CodeBlockView from './code-block-view.svelte'
+
+export function defineCodeBlockView(): Extension {
+  return defineSvelteNodeView({
+    name: 'codeBlock',
+    contentAs: 'code',
+    component: CodeBlockView as SvelteNodeViewComponent,
+  })
+}
diff --git a/sveltekit-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte b/sveltekit-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte
new file mode 100644
index 0000000000..7f6cac1db0
--- /dev/null
+++ b/sveltekit-full/src/components/editor/ui/drop-indicator/drop-indicator.svelte
@@ -0,0 +1,5 @@
+
+
+
diff --git a/sveltekit-full/src/components/editor/ui/drop-indicator/index.ts b/sveltekit-full/src/components/editor/ui/drop-indicator/index.ts
new file mode 100644
index 0000000000..06e89357ed
--- /dev/null
+++ b/sveltekit-full/src/components/editor/ui/drop-indicator/index.ts
@@ -0,0 +1 @@
+export { default as DropIndicator } from './drop-indicator.svelte'
diff --git a/sveltekit-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte b/sveltekit-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
new file mode 100644
index 0000000000..c80af45721
--- /dev/null
+++ b/sveltekit-full/src/components/editor/ui/image-upload-popover/image-upload-popover.svelte
@@ -0,0 +1,121 @@
+
+
+
+  
+    
+  
+
+  
+      {#if !file}
+        
+        
+      {/if}
+
+      {#if !url}
+        
+        
+      {/if}
+
+      {#if url}
+        
+      {/if}
+
+      {#if file}
+        
+      {/if}
+    
+
diff --git a/sveltekit-full/src/components/editor/ui/image-upload-popover/index.ts b/sveltekit-full/src/components/editor/ui/image-upload-popover/index.ts
new file mode 100644
index 0000000000..e53e71c348
--- /dev/null
+++ b/sveltekit-full/src/components/editor/ui/image-upload-popover/index.ts
@@ -0,0 +1 @@
+export { default as ImageUploadPopover } from './image-upload-popover.svelte'
diff --git a/sveltekit-full/src/components/editor/ui/image-view/image-view.svelte b/sveltekit-full/src/components/editor/ui/image-view/image-view.svelte
new file mode 100644
index 0000000000..b8f0fd3971
--- /dev/null
+++ b/sveltekit-full/src/components/editor/ui/image-view/image-view.svelte
@@ -0,0 +1,97 @@
+
+
+ props.setAttrs(event.detail)}
+>
+  {#if url && !error}
+    upload preview
+  {/if}
+  {#if uploading && !error}
+    
+
+
{Math.round(progress * 100)}%
+
+ {/if} + {#if error} +
+
+ +
+ {/if} + +
+
+
diff --git a/sveltekit-full/src/components/editor/ui/image-view/index.ts b/sveltekit-full/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..d39bdb81e8 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,14 @@ +import type { Extension } from 'prosekit/core' +import { + defineSvelteNodeView, + type SvelteNodeViewComponent, +} from 'prosekit/svelte' + +import ImageView from './image-view.svelte' + +export function defineImageView(): Extension { + return defineSvelteNodeView({ + name: 'image', + component: ImageView as SvelteNodeViewComponent, + }) +} diff --git a/sveltekit-full/src/components/editor/ui/inline-menu/index.ts b/sveltekit-full/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..bf78dd2139 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.svelte' diff --git a/sveltekit-full/src/components/editor/ui/inline-menu/inline-menu.svelte b/sveltekit-full/src/components/editor/ui/inline-menu/inline-menu.svelte new file mode 100644 index 0000000000..989f0c013b --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/inline-menu/inline-menu.svelte @@ -0,0 +1,207 @@ + + + { + if (!event.detail) linkMenuOpen = false + }} +> + + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.link?.canExec && $items.link} + + {/if} + + + + + { + linkMenuOpen = event.detail + }} +> + + + {#if linkMenuOpen && $items.link} +
{ + event.preventDefault() + const target = event.target as HTMLFormElement | null + const href = target?.querySelector('input')?.value?.trim() + handleLinkUpdate(href) + }} + > + +
+ {/if} + {#if $items.link?.isActive} + + {/if} +
+
+
diff --git a/sveltekit-full/src/components/editor/ui/slash-menu/index.ts b/sveltekit-full/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..856d4e6b43 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu.svelte' diff --git a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte new file mode 100644 index 0000000000..37cea8de67 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-empty.svelte @@ -0,0 +1,7 @@ + + + + No results + diff --git a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte new file mode 100644 index 0000000000..52126eeb68 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu-item.svelte @@ -0,0 +1,15 @@ + + + + {props.label}{#if props.kbd}{props.kbd}{/if} + diff --git a/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu.svelte b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu.svelte new file mode 100644 index 0000000000..5da516b44f --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/slash-menu/slash-menu.svelte @@ -0,0 +1,94 @@ + + + + + +
+ $editor.commands.setParagraph()} + /> + + $editor.commands.setHeading({ level: 1 })} + /> + + $editor.commands.setHeading({ level: 2 })} + /> + + $editor.commands.setHeading({ level: 3 })} + /> + + $editor.commands.wrapInList({ kind: 'bullet' })} + /> + + $editor.commands.wrapInList({ kind: 'ordered' })} + /> + + $editor.commands.wrapInList({ kind: 'task' })} + /> + + $editor.commands.wrapInList({ kind: 'toggle' })} + /> + + $editor.commands.setBlockquote()} + /> + + $editor.commands.insertTable({ row: 3, col: 3 })} + /> + + $editor.commands.insertHorizontalRule()} + /> + + $editor.commands.setCodeBlock()} + /> + + +
+
+
+
diff --git a/sveltekit-full/src/components/editor/ui/table-handle/index.ts b/sveltekit-full/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..308cef59de --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle.svelte' diff --git a/sveltekit-full/src/components/editor/ui/table-handle/table-handle.svelte b/sveltekit-full/src/components/editor/ui/table-handle/table-handle.svelte new file mode 100644 index 0000000000..fc91f9a438 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/table-handle/table-handle.svelte @@ -0,0 +1,182 @@ + + + + + + + + + +
+
+ + + {#if $state.addTableColumnBefore.canExec} + + Insert Left + + {/if} + {#if $state.addTableColumnAfter.canExec} + + Insert Right + + {/if} + {#if $state.deleteCellSelection.canExec} + + Clear Contents + Del + + {/if} + {#if $state.deleteTableColumn.canExec} + + Delete Column + + {/if} + {#if $state.deleteTable.canExec} + + Delete Table + + {/if} + + +
+
+
+ + + + +
+
+ + + {#if $state.addTableRowAbove.canExec} + + Insert Above + + {/if} + {#if $state.addTableRowBelow.canExec} + + Insert Below + + {/if} + {#if $state.deleteCellSelection.canExec} + + Clear Contents + Del + + {/if} + {#if $state.deleteTableRow.canExec} + + Delete Row + + {/if} + {#if $state.deleteTable.canExec} + + Delete Table + + {/if} + + +
+
+
+
diff --git a/sveltekit-full/src/components/editor/ui/tag-menu/index.ts b/sveltekit-full/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..0884d7f5a1 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu.svelte' diff --git a/sveltekit-full/src/components/editor/ui/tag-menu/tag-menu.svelte b/sveltekit-full/src/components/editor/ui/tag-menu/tag-menu.svelte new file mode 100644 index 0000000000..8b9bf23f30 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/tag-menu/tag-menu.svelte @@ -0,0 +1,53 @@ + + + + + +
+ + No results + + + {#each props.tags as tag (tag.id)} + handleTagInsert(tag.id, tag.label)} + > + #{tag.label} + + {/each} +
+
+
+
diff --git a/sveltekit-full/src/components/editor/ui/toolbar/index.ts b/sveltekit-full/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..7b55cca073 --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.svelte' diff --git a/sveltekit-full/src/components/editor/ui/toolbar/toolbar.svelte b/sveltekit-full/src/components/editor/ui/toolbar/toolbar.svelte new file mode 100644 index 0000000000..49bbeff5aa --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/toolbar/toolbar.svelte @@ -0,0 +1,365 @@ + + +
+ {#if $items.undo} + + {/if} + {#if $items.redo} + + {/if} + + {#if $items.bold} + + {/if} + {#if $items.italic} + + {/if} + {#if $items.underline} + + {/if} + {#if $items.strike} + + {/if} + {#if $items.code} + + {/if} + {#if $items.codeBlock} + + {/if} + {#if $items.heading1} + + {/if} + {#if $items.heading2} + + {/if} + {#if $items.heading3} + + {/if} + {#if $items.horizontalRule} + + {/if} + {#if $items.blockquote} + + {/if} + {#if $items.bulletList} + + {/if} + {#if $items.orderedList} + + {/if} + {#if $items.taskList} + + {/if} + {#if $items.toggleList} + + {/if} + {#if $items.indentList} + + {/if} + {#if $items.dedentList} + + {/if} + {#if uploader && $items.insertImage} + +
+
+ {/if} +
diff --git a/sveltekit-full/src/components/editor/ui/user-menu/index.ts b/sveltekit-full/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..7dbbd80d0e --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu.svelte' diff --git a/sveltekit-full/src/components/editor/ui/user-menu/user-menu.svelte b/sveltekit-full/src/components/editor/ui/user-menu/user-menu.svelte new file mode 100644 index 0000000000..5c0475d87e --- /dev/null +++ b/sveltekit-full/src/components/editor/ui/user-menu/user-menu.svelte @@ -0,0 +1,70 @@ + + + props.onQueryChange?.(event.detail)} + onOpenChange={(event) => props.onOpenChange?.(event.detail)} +> + + +
+ + {loading ? 'Loading...' : 'No results'} + + + {#each props.users as user (user.id)} + handleUserInsert(user.id, user.name)} + > + {#if loading} + + {user.name} + + {:else} + + {user.name} + + {/if} + + {/each} +
+
+
+
diff --git a/sveltekit-full/src/lib/App.svelte b/sveltekit-full/src/lib/App.svelte new file mode 100644 index 0000000000..30118df5d5 --- /dev/null +++ b/sveltekit-full/src/lib/App.svelte @@ -0,0 +1,5 @@ + + + diff --git a/sveltekit-full/src/lib/client-only-editor.svelte b/sveltekit-full/src/lib/client-only-editor.svelte new file mode 100644 index 0000000000..95b9bab68d --- /dev/null +++ b/sveltekit-full/src/lib/client-only-editor.svelte @@ -0,0 +1,14 @@ + + + + diff --git a/sveltekit-full/src/lib/editor.svelte b/sveltekit-full/src/lib/editor.svelte new file mode 100644 index 0000000000..7c89b545c5 --- /dev/null +++ b/sveltekit-full/src/lib/editor.svelte @@ -0,0 +1 @@ +
diff --git a/sveltekit-full/src/routes/+layout.svelte b/sveltekit-full/src/routes/+layout.svelte new file mode 100644 index 0000000000..136e32e64a --- /dev/null +++ b/sveltekit-full/src/routes/+layout.svelte @@ -0,0 +1,5 @@ + + + diff --git a/sveltekit-full/src/routes/+page.svelte b/sveltekit-full/src/routes/+page.svelte new file mode 100644 index 0000000000..590f61d80f --- /dev/null +++ b/sveltekit-full/src/routes/+page.svelte @@ -0,0 +1,7 @@ + + +

Welcome to SvelteKit

+

Visit kit.svelte.dev to read the documentation

+ diff --git a/sveltekit-full/static/favicon.png b/sveltekit-full/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH + + + + + ProseKit + Vanilla TypeScript + + + + + diff --git a/vanilla-minimal/package.json b/vanilla-minimal/package.json new file mode 100644 index 0000000000..167ee07321 --- /dev/null +++ b/vanilla-minimal/package.json @@ -0,0 +1,22 @@ +{ + "name": "example-vanilla-minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "typescript": "~6.0.3", + "vite": "^8.0.13" + } +} diff --git a/vanilla-minimal/src/app.css b/vanilla-minimal/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vanilla-minimal/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vanilla-minimal/src/components/editor/examples/minimal/editor.ts b/vanilla-minimal/src/components/editor/examples/minimal/editor.ts new file mode 100644 index 0000000000..a8ca847e52 --- /dev/null +++ b/vanilla-minimal/src/components/editor/examples/minimal/editor.ts @@ -0,0 +1,22 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { defineBasicExtension } from 'prosekit/basic' +import { createEditor } from 'prosekit/core' + +export function setupVanillaEditor() { + const extension = defineBasicExtension() + const editor = createEditor({ extension }) + + return { + render: () => { + const element = document.createElement('div') + element.className = 'outline-solid p-4' + editor.mount(element) + return element + }, + destroy: () => { + editor.unmount() + }, + } +} diff --git a/vanilla-minimal/src/components/editor/examples/minimal/index.ts b/vanilla-minimal/src/components/editor/examples/minimal/index.ts new file mode 100644 index 0000000000..e54daaa4f4 --- /dev/null +++ b/vanilla-minimal/src/components/editor/examples/minimal/index.ts @@ -0,0 +1 @@ +export { setupVanillaEditor } from './editor' diff --git a/vanilla-minimal/src/editor.ts b/vanilla-minimal/src/editor.ts new file mode 100644 index 0000000000..3ea03142c5 --- /dev/null +++ b/vanilla-minimal/src/editor.ts @@ -0,0 +1,5 @@ +import { setupVanillaEditor } from './components/editor/examples/minimal' + +export function renderEditor() { + return setupVanillaEditor().render() +} diff --git a/vanilla-minimal/src/main.ts b/vanilla-minimal/src/main.ts new file mode 100644 index 0000000000..a4945ae00c --- /dev/null +++ b/vanilla-minimal/src/main.ts @@ -0,0 +1,11 @@ +import './app.css' +import { renderEditor } from './editor' + +let container = document.querySelector('#app') +if (!container) { + container = document.createElement('div') + container.id = 'app' + document.body.appendChild(container) +} + +container.replaceChildren(renderEditor()) diff --git a/vanilla-minimal/tsconfig.json b/vanilla-minimal/tsconfig.json new file mode 100644 index 0000000000..4ba8dd95cf --- /dev/null +++ b/vanilla-minimal/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/vanilla-minimal/vite.config.ts b/vanilla-minimal/vite.config.ts new file mode 100644 index 0000000000..fb0cdf00b5 --- /dev/null +++ b/vanilla-minimal/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [tailwindcss()], +}) diff --git a/vanilla-slash-menu/.gitignore b/vanilla-slash-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vanilla-slash-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vanilla-slash-menu/README.md b/vanilla-slash-menu/README.md new file mode 100644 index 0000000000..0efff88c1b --- /dev/null +++ b/vanilla-slash-menu/README.md @@ -0,0 +1,15 @@ +# vanilla-slash-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vanilla-slash-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vanilla-slash-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vanilla-slash-menu vanilla-slash-menu +cd vanilla-slash-menu +npm install +npm run dev +``` diff --git a/vanilla-slash-menu/index.html b/vanilla-slash-menu/index.html new file mode 100644 index 0000000000..2d9080a6a4 --- /dev/null +++ b/vanilla-slash-menu/index.html @@ -0,0 +1,11 @@ + + + + + + ProseKit + Vanilla TypeScript + + + + + diff --git a/vanilla-slash-menu/package.json b/vanilla-slash-menu/package.json new file mode 100644 index 0000000000..292d295c16 --- /dev/null +++ b/vanilla-slash-menu/package.json @@ -0,0 +1,22 @@ +{ + "name": "example-vanilla-slash-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "tailwindcss": "^4.3.0", + "typescript": "~6.0.3", + "vite": "^8.0.13" + } +} diff --git a/vanilla-slash-menu/src/app.css b/vanilla-slash-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vanilla-slash-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vanilla-slash-menu/src/components/editor/examples/slash-menu/editor.ts b/vanilla-slash-menu/src/components/editor/examples/slash-menu/editor.ts new file mode 100644 index 0000000000..c0e181daa5 --- /dev/null +++ b/vanilla-slash-menu/src/components/editor/examples/slash-menu/editor.ts @@ -0,0 +1,39 @@ +import 'prosekit/basic/style.css' +import 'prosekit/basic/typography.css' + +import { createEditor } from 'prosekit/core' + +import { renderSlashMenu } from '../../ui/slash-menu' + +import { defineExtension } from './extension' + +export function setupVanillaEditor() { + const extension = defineExtension() + const editor = createEditor({ extension }) + + return { + render: () => { + const port = document.createElement('div') + port.className = + 'box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-[canvas] text-black dark:text-white' + + const scrolling = document.createElement('div') + scrolling.className = 'relative w-full flex-1 box-border overflow-y-auto' + port.append(scrolling) + + const content = document.createElement('div') + content.className = + 'ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500' + scrolling.append(content) + + scrolling.append(renderSlashMenu(editor)) + + editor.mount(content) + + return port + }, + destroy: () => { + editor.unmount() + }, + } +} diff --git a/vanilla-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/vanilla-slash-menu/src/components/editor/examples/slash-menu/extension.ts new file mode 100644 index 0000000000..0edda60136 --- /dev/null +++ b/vanilla-slash-menu/src/components/editor/examples/slash-menu/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vanilla-slash-menu/src/components/editor/examples/slash-menu/index.ts b/vanilla-slash-menu/src/components/editor/examples/slash-menu/index.ts new file mode 100644 index 0000000000..e54daaa4f4 --- /dev/null +++ b/vanilla-slash-menu/src/components/editor/examples/slash-menu/index.ts @@ -0,0 +1 @@ +export { setupVanillaEditor } from './editor' diff --git a/vanilla-slash-menu/src/components/editor/ui/slash-menu/index.ts b/vanilla-slash-menu/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..862a5dee51 --- /dev/null +++ b/vanilla-slash-menu/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { renderSlashMenu } from './slash-menu' diff --git a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts new file mode 100644 index 0000000000..cb7d6cbe45 --- /dev/null +++ b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.ts @@ -0,0 +1,17 @@ +import 'prosekit/web/autocomplete' + +import type { AutocompleteEmptyElement } from 'prosekit/web/autocomplete' + +export function renderSlashMenuEmpty() { + const empty = document.createElement( + 'prosekit-autocomplete-empty', + ) as AutocompleteEmptyElement + empty.className = + 'relative flex items-center justify-between min-w-32 scroll-my-1 rounded-md px-3 py-1.5 text-sm box-border cursor-default select-none whitespace-nowrap outline-hidden data-highlighted:bg-gray-100 dark:data-highlighted:bg-gray-800' + + const span = document.createElement('span') + span.textContent = 'No results' + empty.append(span) + + return empty +} diff --git a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts new file mode 100644 index 0000000000..4de0019bf2 --- /dev/null +++ b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.ts @@ -0,0 +1,29 @@ +import 'prosekit/web/autocomplete' + +import type { AutocompleteItemElement } from 'prosekit/web/autocomplete' + +export function renderSlashMenuItem(options: { + label: string + kbd?: string + onSelect: () => void +}) { + const item = document.createElement( + 'prosekit-autocomplete-item', + ) as AutocompleteItemElement + item.className = + 'relative flex items-center justify-between min-w-32 scroll-my-1 rounded-md px-3 py-1.5 text-sm box-border cursor-default select-none whitespace-nowrap outline-hidden data-highlighted:bg-gray-100 dark:data-highlighted:bg-gray-800' + item.addEventListener('select', () => options.onSelect()) + + const span = document.createElement('span') + span.textContent = options.label + item.append(span) + + if (options.kbd) { + const kbd = document.createElement('kbd') + kbd.className = 'text-xs font-mono text-gray-400 dark:text-gray-500' + kbd.textContent = options.kbd + item.append(kbd) + } + + return item +} diff --git a/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts new file mode 100644 index 0000000000..22380d2978 --- /dev/null +++ b/vanilla-slash-menu/src/components/editor/ui/slash-menu/slash-menu.ts @@ -0,0 +1,131 @@ +import 'prosekit/web/autocomplete' + +import type { BasicExtension } from 'prosekit/basic' +import type { Editor } from 'prosekit/core' +import { canUseRegexLookbehind } from 'prosekit/core' +import type { + AutocompletePopupElement, + AutocompletePositionerElement, + AutocompleteRootElement, +} from 'prosekit/web/autocomplete' + +import { renderSlashMenuEmpty } from './slash-menu-empty' +import { renderSlashMenuItem } from './slash-menu-item' + +// Match inputs like "/", "/table", "/heading 1" etc. Do not match "/ heading". +const regex = canUseRegexLookbehind() ? /(?) { + const root = document.createElement( + 'prosekit-autocomplete-root', + ) as AutocompleteRootElement + root.editor = editor + root.regex = regex + + const positioner = document.createElement( + 'prosekit-autocomplete-positioner', + ) as AutocompletePositionerElement + positioner.className = + 'block overflow-visible w-min h-min z-50 ease-out transition-transform duration-100 motion-reduce:transition-none' + + const popup = document.createElement( + 'prosekit-autocomplete-popup', + ) as AutocompletePopupElement + popup.className = + 'box-border origin-(--transform-origin) transition-[opacity,scale] transition-discrete motion-reduce:transition-none data-[state=closed]:duration-150 data-[state=closed]:opacity-0 starting:opacity-0 data-[state=closed]:scale-95 starting:scale-95 duration-40 rounded-xl border border-gray-200 dark:border-gray-800 shadow-lg bg-[canvas] flex flex-col relative max-h-100 min-h-0 min-w-60 select-none overflow-hidden whitespace-nowrap' + + const content = document.createElement('div') + content.className = + 'flex flex-col flex-1 min-h-0 overflow-y-auto p-1 bg-[canvas] overscroll-contain' + + content.append( + renderSlashMenuItem({ + label: 'Text', + kbd: undefined, + onSelect: () => editor.commands.setParagraph(), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Heading 1', + kbd: '#', + onSelect: () => editor.commands.setHeading({ level: 1 }), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Heading 2', + kbd: '##', + onSelect: () => editor.commands.setHeading({ level: 2 }), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Heading 3', + kbd: '###', + onSelect: () => editor.commands.setHeading({ level: 3 }), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Bullet list', + kbd: '-', + onSelect: () => editor.commands.wrapInList({ kind: 'bullet' }), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Ordered list', + kbd: '1.', + onSelect: () => editor.commands.wrapInList({ kind: 'ordered' }), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Task list', + kbd: '[]', + onSelect: () => editor.commands.wrapInList({ kind: 'task' }), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Toggle list', + kbd: '>>', + onSelect: () => editor.commands.wrapInList({ kind: 'toggle' }), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Quote', + kbd: '>', + onSelect: () => editor.commands.setBlockquote(), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Table', + onSelect: () => editor.commands.insertTable({ row: 3, col: 3 }), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Divider', + kbd: '---', + onSelect: () => editor.commands.insertHorizontalRule(), + }), + ) + content.append( + renderSlashMenuItem({ + label: 'Code', + kbd: '```', + onSelect: () => editor.commands.setCodeBlock(), + }), + ) + content.append(renderSlashMenuEmpty()) + + popup.append(content) + positioner.append(popup) + root.append(positioner) + + return root +} diff --git a/vanilla-slash-menu/src/editor.ts b/vanilla-slash-menu/src/editor.ts new file mode 100644 index 0000000000..877138feee --- /dev/null +++ b/vanilla-slash-menu/src/editor.ts @@ -0,0 +1,5 @@ +import { setupVanillaEditor } from './components/editor/examples/slash-menu' + +export function renderEditor() { + return setupVanillaEditor().render() +} diff --git a/vanilla-slash-menu/src/main.ts b/vanilla-slash-menu/src/main.ts new file mode 100644 index 0000000000..a4945ae00c --- /dev/null +++ b/vanilla-slash-menu/src/main.ts @@ -0,0 +1,11 @@ +import './app.css' +import { renderEditor } from './editor' + +let container = document.querySelector('#app') +if (!container) { + container = document.createElement('div') + container.id = 'app' + document.body.appendChild(container) +} + +container.replaceChildren(renderEditor()) diff --git a/vanilla-slash-menu/tsconfig.json b/vanilla-slash-menu/tsconfig.json new file mode 100644 index 0000000000..4ba8dd95cf --- /dev/null +++ b/vanilla-slash-menu/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/vanilla-slash-menu/vite.config.ts b/vanilla-slash-menu/vite.config.ts new file mode 100644 index 0000000000..fb0cdf00b5 --- /dev/null +++ b/vanilla-slash-menu/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import tailwindcss from '@tailwindcss/vite' + +export default defineConfig({ + plugins: [tailwindcss()], +}) diff --git a/vue-block-handle/.gitignore b/vue-block-handle/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-block-handle/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-block-handle/README.md b/vue-block-handle/README.md new file mode 100644 index 0000000000..ec30270abe --- /dev/null +++ b/vue-block-handle/README.md @@ -0,0 +1,15 @@ +# vue-block-handle + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-block-handle) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-block-handle) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-block-handle vue-block-handle +cd vue-block-handle +npm install +npm run dev +``` diff --git a/vue-block-handle/index.html b/vue-block-handle/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-block-handle/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-block-handle/package.json b/vue-block-handle/package.json new file mode 100644 index 0000000000..bddec80eda --- /dev/null +++ b/vue-block-handle/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-block-handle", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-block-handle/src/App.vue b/vue-block-handle/src/App.vue new file mode 100644 index 0000000000..de7bb239b6 --- /dev/null +++ b/vue-block-handle/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-block-handle/src/app.css b/vue-block-handle/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-block-handle/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-block-handle/src/components/editor/examples/block-handle/editor.vue b/vue-block-handle/src/components/editor/examples/block-handle/editor.vue new file mode 100644 index 0000000000..d90d9232bc --- /dev/null +++ b/vue-block-handle/src/components/editor/examples/block-handle/editor.vue @@ -0,0 +1,38 @@ + + + diff --git a/vue-block-handle/src/components/editor/examples/block-handle/extension.ts b/vue-block-handle/src/components/editor/examples/block-handle/extension.ts new file mode 100644 index 0000000000..2c6a5383ad --- /dev/null +++ b/vue-block-handle/src/components/editor/examples/block-handle/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union([defineBasicExtension(), defineCodeBlockView()]) +} + +export type EditorExtension = ReturnType diff --git a/vue-block-handle/src/components/editor/examples/block-handle/index.ts b/vue-block-handle/src/components/editor/examples/block-handle/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-block-handle/src/components/editor/examples/block-handle/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-block-handle/src/components/editor/sample/sample-doc-block-handle.ts b/vue-block-handle/src/components/editor/sample/sample-doc-block-handle.ts new file mode 100644 index 0000000000..3c6ccdc203 --- /dev/null +++ b/vue-block-handle/src/components/editor/sample/sample-doc-block-handle.ts @@ -0,0 +1,323 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Drag and Drop Demo', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try dragging any paragraph or heading by clicking on the handle that appears on the left when you hover over it.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Getting Started', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Hover over any block to see the drag handle appear. Click and drag to reorder content.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This paragraph can be moved above or below other blocks.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Different Block Types', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'You can drag paragraphs, headings, lists, code blocks, and more.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Lists Work Too', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This entire list can be dragged', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Individual list items stay together', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Try moving this list around', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Ordered lists also support dragging', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The numbering updates automatically', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag this list to see it in action', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Even code blocks can be moved:', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: 'javascript', + }, + content: [ + { + type: 'text', + text: '// This code block can be dragged\nfunction dragAndDrop() {\n return "Easy to rearrange!"\n}', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Nested Content', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This blockquote can be moved as a single unit.', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested blockquotes move together with their parent.', + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Try It Yourself', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Practice by moving this paragraph to the top of the document.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Or drag this one to between the headings above.', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The drag handles make it easy to reorganize your content exactly how you want it.', + }, + ], + }, + ], +} diff --git a/vue-block-handle/src/components/editor/ui/block-handle/block-handle.vue b/vue-block-handle/src/components/editor/ui/block-handle/block-handle.vue new file mode 100644 index 0000000000..ba06a1416a --- /dev/null +++ b/vue-block-handle/src/components/editor/ui/block-handle/block-handle.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue-block-handle/src/components/editor/ui/block-handle/index.ts b/vue-block-handle/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..2c33eb5726 --- /dev/null +++ b/vue-block-handle/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.vue' diff --git a/vue-block-handle/src/components/editor/ui/code-block-view/code-block-view.vue b/vue-block-handle/src/components/editor/ui/code-block-view/code-block-view.vue new file mode 100644 index 0000000000..e04ea8792e --- /dev/null +++ b/vue-block-handle/src/components/editor/ui/code-block-view/code-block-view.vue @@ -0,0 +1,41 @@ + + + diff --git a/vue-block-handle/src/components/editor/ui/code-block-view/index.ts b/vue-block-handle/src/components/editor/ui/code-block-view/index.ts new file mode 100644 index 0000000000..b7beb100de --- /dev/null +++ b/vue-block-handle/src/components/editor/ui/code-block-view/index.ts @@ -0,0 +1,12 @@ +import type { Extension } from 'prosekit/core' +import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' + +import CodeBlockView from './code-block-view.vue' + +export function defineCodeBlockView(): Extension { + return defineVueNodeView({ + name: 'codeBlock', + contentAs: 'code', + component: CodeBlockView as VueNodeViewComponent, + }) +} diff --git a/vue-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.vue b/vue-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.vue new file mode 100644 index 0000000000..cac51a8629 --- /dev/null +++ b/vue-block-handle/src/components/editor/ui/drop-indicator/drop-indicator.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-block-handle/src/components/editor/ui/drop-indicator/index.ts b/vue-block-handle/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..b455b1217b --- /dev/null +++ b/vue-block-handle/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator.vue' diff --git a/vue-block-handle/src/main.ts b/vue-block-handle/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-block-handle/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-block-handle/tsconfig.app.json b/vue-block-handle/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-block-handle/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-block-handle/tsconfig.json b/vue-block-handle/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-block-handle/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-block-handle/tsconfig.node.json b/vue-block-handle/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-block-handle/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-block-handle/vite.config.ts b/vue-block-handle/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-block-handle/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-blockquote/.gitignore b/vue-blockquote/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-blockquote/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-blockquote/README.md b/vue-blockquote/README.md new file mode 100644 index 0000000000..db02e76337 --- /dev/null +++ b/vue-blockquote/README.md @@ -0,0 +1,15 @@ +# vue-blockquote + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-blockquote) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-blockquote) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-blockquote vue-blockquote +cd vue-blockquote +npm install +npm run dev +``` diff --git a/vue-blockquote/index.html b/vue-blockquote/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-blockquote/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-blockquote/package.json b/vue-blockquote/package.json new file mode 100644 index 0000000000..b2f8ef7864 --- /dev/null +++ b/vue-blockquote/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-blockquote", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-blockquote/src/App.vue b/vue-blockquote/src/App.vue new file mode 100644 index 0000000000..b931971697 --- /dev/null +++ b/vue-blockquote/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-blockquote/src/app.css b/vue-blockquote/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-blockquote/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-blockquote/src/components/editor/examples/blockquote/editor.vue b/vue-blockquote/src/components/editor/examples/blockquote/editor.vue new file mode 100644 index 0000000000..7d4edcece6 --- /dev/null +++ b/vue-blockquote/src/components/editor/examples/blockquote/editor.vue @@ -0,0 +1,30 @@ + + + diff --git a/vue-blockquote/src/components/editor/examples/blockquote/extension.ts b/vue-blockquote/src/components/editor/examples/blockquote/extension.ts new file mode 100644 index 0000000000..5292b59e35 --- /dev/null +++ b/vue-blockquote/src/components/editor/examples/blockquote/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBlockquote(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-blockquote/src/components/editor/examples/blockquote/index.ts b/vue-blockquote/src/components/editor/examples/blockquote/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-blockquote/src/components/editor/examples/blockquote/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-blockquote/src/components/editor/ui/button/button.vue b/vue-blockquote/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-blockquote/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-blockquote/src/components/editor/ui/button/index.ts b/vue-blockquote/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-blockquote/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-blockquote/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-blockquote/src/components/editor/ui/image-upload-popover/index.ts b/vue-blockquote/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-blockquote/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-blockquote/src/components/editor/ui/toolbar/index.ts b/vue-blockquote/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-blockquote/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-blockquote/src/components/editor/ui/toolbar/toolbar.vue b/vue-blockquote/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-blockquote/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-blockquote/src/main.ts b/vue-blockquote/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-blockquote/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-blockquote/tsconfig.app.json b/vue-blockquote/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-blockquote/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-blockquote/tsconfig.json b/vue-blockquote/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-blockquote/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-blockquote/tsconfig.node.json b/vue-blockquote/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-blockquote/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-blockquote/vite.config.ts b/vue-blockquote/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-blockquote/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-bold/.gitignore b/vue-bold/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-bold/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-bold/README.md b/vue-bold/README.md new file mode 100644 index 0000000000..0d17b69b30 --- /dev/null +++ b/vue-bold/README.md @@ -0,0 +1,15 @@ +# vue-bold + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-bold) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-bold) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-bold vue-bold +cd vue-bold +npm install +npm run dev +``` diff --git a/vue-bold/index.html b/vue-bold/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-bold/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-bold/package.json b/vue-bold/package.json new file mode 100644 index 0000000000..86123b8d61 --- /dev/null +++ b/vue-bold/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-bold", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-bold/src/App.vue b/vue-bold/src/App.vue new file mode 100644 index 0000000000..bb01967f7f --- /dev/null +++ b/vue-bold/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-bold/src/app.css b/vue-bold/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-bold/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-bold/src/components/editor/examples/bold/editor.vue b/vue-bold/src/components/editor/examples/bold/editor.vue new file mode 100644 index 0000000000..2987d333aa --- /dev/null +++ b/vue-bold/src/components/editor/examples/bold/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-bold/src/components/editor/examples/bold/extension.ts b/vue-bold/src/components/editor/examples/bold/extension.ts new file mode 100644 index 0000000000..eaa4fba721 --- /dev/null +++ b/vue-bold/src/components/editor/examples/bold/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineBold } from 'prosekit/extensions/bold' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineBold(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-bold/src/components/editor/examples/bold/index.ts b/vue-bold/src/components/editor/examples/bold/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-bold/src/components/editor/examples/bold/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-bold/src/components/editor/sample/sample-doc-bold.ts b/vue-bold/src/components/editor/sample/sample-doc-bold.ts new file mode 100644 index 0000000000..09ed08daad --- /dev/null +++ b/vue-bold/src/components/editor/sample/sample-doc-bold.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'This is bold too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/vue-bold/src/components/editor/ui/button/button.vue b/vue-bold/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-bold/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-bold/src/components/editor/ui/button/index.ts b/vue-bold/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-bold/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-bold/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-bold/src/components/editor/ui/image-upload-popover/index.ts b/vue-bold/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-bold/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-bold/src/components/editor/ui/toolbar/index.ts b/vue-bold/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-bold/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-bold/src/components/editor/ui/toolbar/toolbar.vue b/vue-bold/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-bold/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-bold/src/main.ts b/vue-bold/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-bold/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-bold/tsconfig.app.json b/vue-bold/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-bold/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-bold/tsconfig.json b/vue-bold/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-bold/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-bold/tsconfig.node.json b/vue-bold/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-bold/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-bold/vite.config.ts b/vue-bold/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-bold/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-change-tracking/.gitignore b/vue-change-tracking/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-change-tracking/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-change-tracking/README.md b/vue-change-tracking/README.md new file mode 100644 index 0000000000..0ca20f42f9 --- /dev/null +++ b/vue-change-tracking/README.md @@ -0,0 +1,15 @@ +# vue-change-tracking + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-change-tracking) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-change-tracking) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-change-tracking vue-change-tracking +cd vue-change-tracking +npm install +npm run dev +``` diff --git a/vue-change-tracking/index.html b/vue-change-tracking/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-change-tracking/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-change-tracking/package.json b/vue-change-tracking/package.json new file mode 100644 index 0000000000..35550fcd79 --- /dev/null +++ b/vue-change-tracking/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-change-tracking", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-change-tracking/src/App.vue b/vue-change-tracking/src/App.vue new file mode 100644 index 0000000000..6d4c9d0394 --- /dev/null +++ b/vue-change-tracking/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-change-tracking/src/app.css b/vue-change-tracking/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-change-tracking/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-change-tracking/src/components/editor/examples/change-tracking/editor-diff.vue b/vue-change-tracking/src/components/editor/examples/change-tracking/editor-diff.vue new file mode 100644 index 0000000000..8825343c7e --- /dev/null +++ b/vue-change-tracking/src/components/editor/examples/change-tracking/editor-diff.vue @@ -0,0 +1,32 @@ + + + diff --git a/vue-change-tracking/src/components/editor/examples/change-tracking/editor-main.vue b/vue-change-tracking/src/components/editor/examples/change-tracking/editor-main.vue new file mode 100644 index 0000000000..93724a8157 --- /dev/null +++ b/vue-change-tracking/src/components/editor/examples/change-tracking/editor-main.vue @@ -0,0 +1,40 @@ + + + diff --git a/vue-change-tracking/src/components/editor/examples/change-tracking/editor.vue b/vue-change-tracking/src/components/editor/examples/change-tracking/editor.vue new file mode 100644 index 0000000000..08d3bb77d9 --- /dev/null +++ b/vue-change-tracking/src/components/editor/examples/change-tracking/editor.vue @@ -0,0 +1,71 @@ + + + diff --git a/vue-change-tracking/src/components/editor/examples/change-tracking/index.ts b/vue-change-tracking/src/components/editor/examples/change-tracking/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-change-tracking/src/components/editor/examples/change-tracking/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-change-tracking/src/main.ts b/vue-change-tracking/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-change-tracking/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-change-tracking/tsconfig.app.json b/vue-change-tracking/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-change-tracking/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-change-tracking/tsconfig.json b/vue-change-tracking/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-change-tracking/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-change-tracking/tsconfig.node.json b/vue-change-tracking/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-change-tracking/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-change-tracking/vite.config.ts b/vue-change-tracking/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-change-tracking/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-code-block-themes/.gitignore b/vue-code-block-themes/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-code-block-themes/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-code-block-themes/README.md b/vue-code-block-themes/README.md new file mode 100644 index 0000000000..b7662cb7dc --- /dev/null +++ b/vue-code-block-themes/README.md @@ -0,0 +1,15 @@ +# vue-code-block-themes + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-code-block-themes) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-code-block-themes) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-code-block-themes vue-code-block-themes +cd vue-code-block-themes +npm install +npm run dev +``` diff --git a/vue-code-block-themes/index.html b/vue-code-block-themes/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-code-block-themes/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-code-block-themes/package.json b/vue-code-block-themes/package.json new file mode 100644 index 0000000000..875dde166c --- /dev/null +++ b/vue-code-block-themes/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-code-block-themes", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-code-block-themes/src/App.vue b/vue-code-block-themes/src/App.vue new file mode 100644 index 0000000000..4c1eff8f81 --- /dev/null +++ b/vue-code-block-themes/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-code-block-themes/src/app.css b/vue-code-block-themes/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-code-block-themes/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/editor.vue b/vue-code-block-themes/src/components/editor/examples/code-block-themes/editor.vue new file mode 100644 index 0000000000..447334d101 --- /dev/null +++ b/vue-code-block-themes/src/components/editor/examples/code-block-themes/editor.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts b/vue-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts new file mode 100644 index 0000000000..b5686b8c04 --- /dev/null +++ b/vue-code-block-themes/src/components/editor/examples/code-block-themes/extension.ts @@ -0,0 +1,10 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union(defineBasicExtension(), defineCodeBlockView()) +} + +export type EditorExtension = ReturnType diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/index.ts b/vue-code-block-themes/src/components/editor/examples/code-block-themes/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-code-block-themes/src/components/editor/examples/code-block-themes/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.vue b/vue-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.vue new file mode 100644 index 0000000000..d248f3115e --- /dev/null +++ b/vue-code-block-themes/src/components/editor/examples/code-block-themes/theme-selector.vue @@ -0,0 +1,33 @@ + + + diff --git a/vue-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.vue b/vue-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.vue new file mode 100644 index 0000000000..3d86fafb76 --- /dev/null +++ b/vue-code-block-themes/src/components/editor/examples/code-block-themes/toolbar.vue @@ -0,0 +1,11 @@ + + + diff --git a/vue-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts b/vue-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/vue-code-block-themes/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/vue-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.vue b/vue-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.vue new file mode 100644 index 0000000000..e04ea8792e --- /dev/null +++ b/vue-code-block-themes/src/components/editor/ui/code-block-view/code-block-view.vue @@ -0,0 +1,41 @@ + + + diff --git a/vue-code-block-themes/src/components/editor/ui/code-block-view/index.ts b/vue-code-block-themes/src/components/editor/ui/code-block-view/index.ts new file mode 100644 index 0000000000..b7beb100de --- /dev/null +++ b/vue-code-block-themes/src/components/editor/ui/code-block-view/index.ts @@ -0,0 +1,12 @@ +import type { Extension } from 'prosekit/core' +import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' + +import CodeBlockView from './code-block-view.vue' + +export function defineCodeBlockView(): Extension { + return defineVueNodeView({ + name: 'codeBlock', + contentAs: 'code', + component: CodeBlockView as VueNodeViewComponent, + }) +} diff --git a/vue-code-block-themes/src/main.ts b/vue-code-block-themes/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-code-block-themes/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-code-block-themes/tsconfig.app.json b/vue-code-block-themes/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-code-block-themes/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-code-block-themes/tsconfig.json b/vue-code-block-themes/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-code-block-themes/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-code-block-themes/tsconfig.node.json b/vue-code-block-themes/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-code-block-themes/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-code-block-themes/vite.config.ts b/vue-code-block-themes/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-code-block-themes/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-code-block/.gitignore b/vue-code-block/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-code-block/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-code-block/README.md b/vue-code-block/README.md new file mode 100644 index 0000000000..f369822592 --- /dev/null +++ b/vue-code-block/README.md @@ -0,0 +1,15 @@ +# vue-code-block + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-code-block) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-code-block) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-code-block vue-code-block +cd vue-code-block +npm install +npm run dev +``` diff --git a/vue-code-block/index.html b/vue-code-block/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-code-block/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-code-block/package.json b/vue-code-block/package.json new file mode 100644 index 0000000000..6452d01fc5 --- /dev/null +++ b/vue-code-block/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-code-block", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-code-block/src/App.vue b/vue-code-block/src/App.vue new file mode 100644 index 0000000000..9df9382264 --- /dev/null +++ b/vue-code-block/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-code-block/src/app.css b/vue-code-block/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-code-block/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-code-block/src/components/editor/examples/code-block/editor.vue b/vue-code-block/src/components/editor/examples/code-block/editor.vue new file mode 100644 index 0000000000..732a47de8b --- /dev/null +++ b/vue-code-block/src/components/editor/examples/code-block/editor.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue-code-block/src/components/editor/examples/code-block/extension.ts b/vue-code-block/src/components/editor/examples/code-block/extension.ts new file mode 100644 index 0000000000..099cacf03b --- /dev/null +++ b/vue-code-block/src/components/editor/examples/code-block/extension.ts @@ -0,0 +1,24 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { + defineCodeBlock, + defineCodeBlockShiki, +} from 'prosekit/extensions/code-block' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +import { defineCodeBlockView } from '../../ui/code-block-view' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCodeBlock(), + defineCodeBlockShiki(), + defineCodeBlockView(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-code-block/src/components/editor/examples/code-block/index.ts b/vue-code-block/src/components/editor/examples/code-block/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-code-block/src/components/editor/examples/code-block/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-code-block/src/components/editor/sample/sample-doc-code-block.ts b/vue-code-block/src/components/editor/sample/sample-doc-code-block.ts new file mode 100644 index 0000000000..dc3c3020e4 --- /dev/null +++ b/vue-code-block/src/components/editor/sample/sample-doc-code-block.ts @@ -0,0 +1,50 @@ +import type { NodeJSON } from 'prosekit/core' + +const js = ` +async function start() { + while (true) { + await sleep() + await eat() + await code('JavaScript!') + } +} +`.trim() + +const py = ` +async def start(): + while True: + await sleep() + await eat() + await code('Python!') +`.trim() + +const go = ` +func start() { + for { + sleep() + eat() + code('Go!') + } +} +`.trim() + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [{ type: 'text', text: js }], + }, + { + type: 'codeBlock', + attrs: { language: 'python' }, + content: [{ type: 'text', text: py }], + }, + { + type: 'codeBlock', + attrs: { language: 'go' }, + content: [{ type: 'text', text: go }], + }, + ], +} diff --git a/vue-code-block/src/components/editor/ui/button/button.vue b/vue-code-block/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-code-block/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-code-block/src/components/editor/ui/button/index.ts b/vue-code-block/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-code-block/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-code-block/src/components/editor/ui/code-block-view/code-block-view.vue b/vue-code-block/src/components/editor/ui/code-block-view/code-block-view.vue new file mode 100644 index 0000000000..e04ea8792e --- /dev/null +++ b/vue-code-block/src/components/editor/ui/code-block-view/code-block-view.vue @@ -0,0 +1,41 @@ + + + diff --git a/vue-code-block/src/components/editor/ui/code-block-view/index.ts b/vue-code-block/src/components/editor/ui/code-block-view/index.ts new file mode 100644 index 0000000000..b7beb100de --- /dev/null +++ b/vue-code-block/src/components/editor/ui/code-block-view/index.ts @@ -0,0 +1,12 @@ +import type { Extension } from 'prosekit/core' +import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' + +import CodeBlockView from './code-block-view.vue' + +export function defineCodeBlockView(): Extension { + return defineVueNodeView({ + name: 'codeBlock', + contentAs: 'code', + component: CodeBlockView as VueNodeViewComponent, + }) +} diff --git a/vue-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-code-block/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-code-block/src/components/editor/ui/image-upload-popover/index.ts b/vue-code-block/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-code-block/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-code-block/src/components/editor/ui/toolbar/index.ts b/vue-code-block/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-code-block/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-code-block/src/components/editor/ui/toolbar/toolbar.vue b/vue-code-block/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-code-block/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-code-block/src/main.ts b/vue-code-block/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-code-block/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-code-block/tsconfig.app.json b/vue-code-block/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-code-block/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-code-block/tsconfig.json b/vue-code-block/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-code-block/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-code-block/tsconfig.node.json b/vue-code-block/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-code-block/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-code-block/vite.config.ts b/vue-code-block/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-code-block/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-code/.gitignore b/vue-code/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-code/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-code/README.md b/vue-code/README.md new file mode 100644 index 0000000000..4dc6dfc31e --- /dev/null +++ b/vue-code/README.md @@ -0,0 +1,15 @@ +# vue-code + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-code) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-code) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-code vue-code +cd vue-code +npm install +npm run dev +``` diff --git a/vue-code/index.html b/vue-code/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-code/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-code/package.json b/vue-code/package.json new file mode 100644 index 0000000000..3fbec58fa3 --- /dev/null +++ b/vue-code/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-code", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-code/src/App.vue b/vue-code/src/App.vue new file mode 100644 index 0000000000..debe2e237b --- /dev/null +++ b/vue-code/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-code/src/app.css b/vue-code/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-code/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-code/src/components/editor/examples/code/editor.vue b/vue-code/src/components/editor/examples/code/editor.vue new file mode 100644 index 0000000000..c0b860042b --- /dev/null +++ b/vue-code/src/components/editor/examples/code/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-code/src/components/editor/examples/code/extension.ts b/vue-code/src/components/editor/examples/code/extension.ts new file mode 100644 index 0000000000..e9e273216e --- /dev/null +++ b/vue-code/src/components/editor/examples/code/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineCode(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-code/src/components/editor/examples/code/index.ts b/vue-code/src/components/editor/examples/code/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-code/src/components/editor/examples/code/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-code/src/components/editor/sample/sample-doc-code.ts b/vue-code/src/components/editor/sample/sample-doc-code.ts new file mode 100644 index 0000000000..2fdbcee1f3 --- /dev/null +++ b/vue-code/src/components/editor/sample/sample-doc-code.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'This is code', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/vue-code/src/components/editor/ui/button/button.vue b/vue-code/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-code/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-code/src/components/editor/ui/button/index.ts b/vue-code/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-code/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-code/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-code/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-code/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-code/src/components/editor/ui/image-upload-popover/index.ts b/vue-code/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-code/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-code/src/components/editor/ui/toolbar/index.ts b/vue-code/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-code/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-code/src/components/editor/ui/toolbar/toolbar.vue b/vue-code/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-code/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-code/src/main.ts b/vue-code/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-code/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-code/tsconfig.app.json b/vue-code/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-code/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-code/tsconfig.json b/vue-code/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-code/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-code/tsconfig.node.json b/vue-code/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-code/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-code/vite.config.ts b/vue-code/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-code/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-drop-cursor/.gitignore b/vue-drop-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-drop-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-drop-cursor/README.md b/vue-drop-cursor/README.md new file mode 100644 index 0000000000..229ed15f7a --- /dev/null +++ b/vue-drop-cursor/README.md @@ -0,0 +1,15 @@ +# vue-drop-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-drop-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-drop-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-drop-cursor vue-drop-cursor +cd vue-drop-cursor +npm install +npm run dev +``` diff --git a/vue-drop-cursor/index.html b/vue-drop-cursor/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-drop-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-drop-cursor/package.json b/vue-drop-cursor/package.json new file mode 100644 index 0000000000..1676093f1a --- /dev/null +++ b/vue-drop-cursor/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-drop-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-drop-cursor/src/App.vue b/vue-drop-cursor/src/App.vue new file mode 100644 index 0000000000..14188942fc --- /dev/null +++ b/vue-drop-cursor/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-drop-cursor/src/app.css b/vue-drop-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-drop-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-drop-cursor/src/components/editor/examples/drop-cursor/editor.vue b/vue-drop-cursor/src/components/editor/examples/drop-cursor/editor.vue new file mode 100644 index 0000000000..1ac7fc47f3 --- /dev/null +++ b/vue-drop-cursor/src/components/editor/examples/drop-cursor/editor.vue @@ -0,0 +1,34 @@ + + + diff --git a/vue-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts b/vue-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts new file mode 100644 index 0000000000..fd79a2c96c --- /dev/null +++ b/vue-drop-cursor/src/components/editor/examples/drop-cursor/extension.ts @@ -0,0 +1,23 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineImage(), + defineDropCursor({ + color: false, + width: 4, + class: 'transition-all bg-blue-500', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-drop-cursor/src/components/editor/examples/drop-cursor/index.ts b/vue-drop-cursor/src/components/editor/examples/drop-cursor/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-drop-cursor/src/components/editor/examples/drop-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts b/vue-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts new file mode 100644 index 0000000000..22c6b93465 --- /dev/null +++ b/vue-drop-cursor/src/components/editor/sample/sample-doc-drop-cursor.ts @@ -0,0 +1,40 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the images below to see the custom drop cursor.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/320x240/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/green/320x240/40', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blue/320x240/187', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/red/320x240/188', + }, + }, + ], +} diff --git a/vue-drop-cursor/src/main.ts b/vue-drop-cursor/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-drop-cursor/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-drop-cursor/tsconfig.app.json b/vue-drop-cursor/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-drop-cursor/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-drop-cursor/tsconfig.json b/vue-drop-cursor/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-drop-cursor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-drop-cursor/tsconfig.node.json b/vue-drop-cursor/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-drop-cursor/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-drop-cursor/vite.config.ts b/vue-drop-cursor/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-drop-cursor/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-emoji-rules/.gitignore b/vue-emoji-rules/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-emoji-rules/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-emoji-rules/README.md b/vue-emoji-rules/README.md new file mode 100644 index 0000000000..a47eaa9016 --- /dev/null +++ b/vue-emoji-rules/README.md @@ -0,0 +1,15 @@ +# vue-emoji-rules + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-emoji-rules) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-emoji-rules) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-emoji-rules vue-emoji-rules +cd vue-emoji-rules +npm install +npm run dev +``` diff --git a/vue-emoji-rules/index.html b/vue-emoji-rules/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-emoji-rules/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-emoji-rules/package.json b/vue-emoji-rules/package.json new file mode 100644 index 0000000000..880cf6cc37 --- /dev/null +++ b/vue-emoji-rules/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-emoji-rules", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-emoji-rules/src/App.vue b/vue-emoji-rules/src/App.vue new file mode 100644 index 0000000000..c88e4f810f --- /dev/null +++ b/vue-emoji-rules/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-emoji-rules/src/app.css b/vue-emoji-rules/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-emoji-rules/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-emoji-rules/src/components/editor/examples/emoji-rules/editor.vue b/vue-emoji-rules/src/components/editor/examples/emoji-rules/editor.vue new file mode 100644 index 0000000000..d8707ded7c --- /dev/null +++ b/vue-emoji-rules/src/components/editor/examples/emoji-rules/editor.vue @@ -0,0 +1,27 @@ + + + diff --git a/vue-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts b/vue-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts new file mode 100644 index 0000000000..5cac9cbc79 --- /dev/null +++ b/vue-emoji-rules/src/components/editor/examples/emoji-rules/emoji.ts @@ -0,0 +1,15 @@ +import { defineEnterRule } from 'prosekit/extensions/enter-rule' + +/** + * Converts the text before the text cursor into an emoji when pressing `Enter`. + */ +export function defineEmojiEnterRule() { + return defineEnterRule({ + regex: /:(apple|banana):$/, + handler: ({ match, from, to, state }) => { + const text = match[1] as 'apple' | 'banana' + const emoji = text === 'apple' ? '🍎' : '🍌' + return state.tr.replaceWith(from, to, state.schema.text(emoji)) + }, + }) +} diff --git a/vue-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts b/vue-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts new file mode 100644 index 0000000000..bc9bcb8412 --- /dev/null +++ b/vue-emoji-rules/src/components/editor/examples/emoji-rules/extension.ts @@ -0,0 +1,15 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { defineEmojiEnterRule } from './emoji' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineEmojiEnterRule(), + definePlaceholder({ placeholder: 'Try typing :apple: then press Enter' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-emoji-rules/src/components/editor/examples/emoji-rules/index.ts b/vue-emoji-rules/src/components/editor/examples/emoji-rules/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-emoji-rules/src/components/editor/examples/emoji-rules/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-emoji-rules/src/main.ts b/vue-emoji-rules/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-emoji-rules/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-emoji-rules/tsconfig.app.json b/vue-emoji-rules/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-emoji-rules/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-emoji-rules/tsconfig.json b/vue-emoji-rules/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-emoji-rules/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-emoji-rules/tsconfig.node.json b/vue-emoji-rules/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-emoji-rules/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-emoji-rules/vite.config.ts b/vue-emoji-rules/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-emoji-rules/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-full/.gitignore b/vue-full/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-full/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-full/README.md b/vue-full/README.md new file mode 100644 index 0000000000..ac4740405a --- /dev/null +++ b/vue-full/README.md @@ -0,0 +1,15 @@ +# vue-full + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-full) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-full) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-full vue-full +cd vue-full +npm install +npm run dev +``` diff --git a/vue-full/index.html b/vue-full/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-full/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-full/package.json b/vue-full/package.json new file mode 100644 index 0000000000..5e60cfbe49 --- /dev/null +++ b/vue-full/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-vue-full", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-full/src/App.vue b/vue-full/src/App.vue new file mode 100644 index 0000000000..560ed9299f --- /dev/null +++ b/vue-full/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-full/src/app.css b/vue-full/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-full/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-full/src/components/editor/examples/full/editor.vue b/vue-full/src/components/editor/examples/full/editor.vue new file mode 100644 index 0000000000..a81ba14ef8 --- /dev/null +++ b/vue-full/src/components/editor/examples/full/editor.vue @@ -0,0 +1,53 @@ + + + diff --git a/vue-full/src/components/editor/examples/full/extension.ts b/vue-full/src/components/editor/examples/full/extension.ts new file mode 100644 index 0000000000..5fc2f60685 --- /dev/null +++ b/vue-full/src/components/editor/examples/full/extension.ts @@ -0,0 +1,34 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineCodeBlockShiki } from 'prosekit/extensions/code-block' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineImageUploadHandler } from 'prosekit/extensions/image' +import { defineMath } from 'prosekit/extensions/math' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' +import { sampleUploader } from '../../sample/sample-uploader' +import { defineCodeBlockView } from '../../ui/code-block-view' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + defineMention(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + defineCodeBlockShiki(), + defineHorizontalRule(), + defineCodeBlockView(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-full/src/components/editor/examples/full/index.ts b/vue-full/src/components/editor/examples/full/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-full/src/components/editor/examples/full/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-full/src/components/editor/sample/katex.ts b/vue-full/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/vue-full/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/vue-full/src/components/editor/sample/sample-doc-full.ts b/vue-full/src/components/editor/sample/sample-doc-full.ts new file mode 100644 index 0000000000..13e49b634d --- /dev/null +++ b/vue-full/src/components/editor/sample/sample-doc-full.ts @@ -0,0 +1,442 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'The editor that thinks like you' }], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Every keystroke flows naturally. Every feature appears exactly when you need it. This is ', + }, + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'writing without barriers', + }, + { type: 'text', text: '.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Text that shines.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Make your words ' }, + { type: 'text', marks: [{ type: 'bold' }], text: 'bold' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'italic' }], text: 'italic' }, + { type: 'text', text: ', ' }, + { type: 'text', marks: [{ type: 'underline' }], text: 'underlined' }, + { type: 'text', text: ', or ' }, + { type: 'text', marks: [{ type: 'strike' }], text: 'crossed out' }, + { type: 'text', text: '. Add ' }, + { type: 'text', marks: [{ type: 'code' }], text: 'inline code' }, + { type: 'text', text: ' that stands out. Create ' }, + { + type: 'text', + marks: [{ type: 'link', attrs: { href: 'https://prosekit.dev' } }], + text: 'links', + }, + { type: 'text', text: ' that connect.' }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Select any text to format it. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '@' }, + { type: 'text', text: ' to mention ' }, + { + type: 'mention', + attrs: { id: '39', value: '@someone', kind: 'user' }, + }, + { type: 'text', text: ' or ' }, + { type: 'text', marks: [{ type: 'code' }], text: '#' }, + { type: 'text', text: ' for ' }, + { type: 'mention', attrs: { id: '1', value: '#topics', kind: 'tag' } }, + { type: 'text', text: '. Press ' }, + { type: 'text', marks: [{ type: 'code' }], text: '/' }, + { type: 'text', text: " and discover what's possible." }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Lists that organize.' }], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Bullet points that guide thoughts' }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Nested lists for complex ideas' }], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sub-points flow naturally' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'bullet', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Tasks that focus' }], + }, + { + type: 'list', + attrs: { kind: 'task', order: null, checked: true, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Done feels good' }], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Todo drives action' }], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Numbered steps' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Sequential thinking' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered', order: null, checked: false, collapsed: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Clear progress' }], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Code that inspires.' }], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: '// Code that reads like poetry\nconst magic = createEditor()\nmagic.transform(thoughts)\n', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Images that captivate.' }], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/season/320x240/107', + }, + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Drag the handle in the bottom right corner to resize.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Tables that structure.' }], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'Feature', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [{ type: 'bold' }], + text: 'How to use', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', marks: [{ type: 'bold' }], text: 'Result' }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Format text' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Select and choose' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Perfect styling' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Add mentions' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Type @ and name' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Connected ideas' }], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Insert anything' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Press / for menu' }], + }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Endless possibilities' }], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Math that renders.' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Inline math like ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' appears within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Quotes that inspire.' }], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: '"This is not just an editor. This is how writing should feel."', + }, + ], + }, + ], + }, + { type: 'horizontalRule' }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Start typing. Everything else just flows.' }, + ], + }, + ], +} diff --git a/vue-full/src/components/editor/sample/sample-tag-data.ts b/vue-full/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/vue-full/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/vue-full/src/components/editor/sample/sample-uploader.ts b/vue-full/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/vue-full/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/vue-full/src/components/editor/sample/sample-user-data.ts b/vue-full/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/vue-full/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/vue-full/src/components/editor/ui/block-handle/block-handle.vue b/vue-full/src/components/editor/ui/block-handle/block-handle.vue new file mode 100644 index 0000000000..ba06a1416a --- /dev/null +++ b/vue-full/src/components/editor/ui/block-handle/block-handle.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue-full/src/components/editor/ui/block-handle/index.ts b/vue-full/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..2c33eb5726 --- /dev/null +++ b/vue-full/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.vue' diff --git a/vue-full/src/components/editor/ui/button/button.vue b/vue-full/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-full/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-full/src/components/editor/ui/button/index.ts b/vue-full/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-full/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-full/src/components/editor/ui/code-block-view/code-block-view.vue b/vue-full/src/components/editor/ui/code-block-view/code-block-view.vue new file mode 100644 index 0000000000..e04ea8792e --- /dev/null +++ b/vue-full/src/components/editor/ui/code-block-view/code-block-view.vue @@ -0,0 +1,41 @@ + + + diff --git a/vue-full/src/components/editor/ui/code-block-view/index.ts b/vue-full/src/components/editor/ui/code-block-view/index.ts new file mode 100644 index 0000000000..b7beb100de --- /dev/null +++ b/vue-full/src/components/editor/ui/code-block-view/index.ts @@ -0,0 +1,12 @@ +import type { Extension } from 'prosekit/core' +import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' + +import CodeBlockView from './code-block-view.vue' + +export function defineCodeBlockView(): Extension { + return defineVueNodeView({ + name: 'codeBlock', + contentAs: 'code', + component: CodeBlockView as VueNodeViewComponent, + }) +} diff --git a/vue-full/src/components/editor/ui/drop-indicator/drop-indicator.vue b/vue-full/src/components/editor/ui/drop-indicator/drop-indicator.vue new file mode 100644 index 0000000000..cac51a8629 --- /dev/null +++ b/vue-full/src/components/editor/ui/drop-indicator/drop-indicator.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-full/src/components/editor/ui/drop-indicator/index.ts b/vue-full/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..b455b1217b --- /dev/null +++ b/vue-full/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator.vue' diff --git a/vue-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-full/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-full/src/components/editor/ui/image-upload-popover/index.ts b/vue-full/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-full/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-full/src/components/editor/ui/image-view/image-view.vue b/vue-full/src/components/editor/ui/image-view/image-view.vue new file mode 100644 index 0000000000..a8beb8acd2 --- /dev/null +++ b/vue-full/src/components/editor/ui/image-view/image-view.vue @@ -0,0 +1,97 @@ + + + diff --git a/vue-full/src/components/editor/ui/image-view/index.ts b/vue-full/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..960e2c64d6 --- /dev/null +++ b/vue-full/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,11 @@ +import type { Extension } from 'prosekit/core' +import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' + +import ImageView from './image-view.vue' + +export function defineImageView(): Extension { + return defineVueNodeView({ + name: 'image', + component: ImageView as VueNodeViewComponent, + }) +} diff --git a/vue-full/src/components/editor/ui/inline-menu/index.ts b/vue-full/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8c72e460c8 --- /dev/null +++ b/vue-full/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-full/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-full/src/components/editor/ui/inline-menu/inline-menu.vue new file mode 100644 index 0000000000..cacb76b189 --- /dev/null +++ b/vue-full/src/components/editor/ui/inline-menu/inline-menu.vue @@ -0,0 +1,219 @@ + + + diff --git a/vue-full/src/components/editor/ui/slash-menu/index.ts b/vue-full/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..32d71d61f5 --- /dev/null +++ b/vue-full/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu.vue' diff --git a/vue-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue b/vue-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue new file mode 100644 index 0000000000..50fc5468fb --- /dev/null +++ b/vue-full/src/components/editor/ui/slash-menu/slash-menu-empty.vue @@ -0,0 +1,11 @@ + + + diff --git a/vue-full/src/components/editor/ui/slash-menu/slash-menu-item.vue b/vue-full/src/components/editor/ui/slash-menu/slash-menu-item.vue new file mode 100644 index 0000000000..2d99363b45 --- /dev/null +++ b/vue-full/src/components/editor/ui/slash-menu/slash-menu-item.vue @@ -0,0 +1,24 @@ + + + diff --git a/vue-full/src/components/editor/ui/slash-menu/slash-menu.vue b/vue-full/src/components/editor/ui/slash-menu/slash-menu.vue new file mode 100644 index 0000000000..87090511e3 --- /dev/null +++ b/vue-full/src/components/editor/ui/slash-menu/slash-menu.vue @@ -0,0 +1,106 @@ + + + diff --git a/vue-full/src/components/editor/ui/table-handle/index.ts b/vue-full/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..0132b96b36 --- /dev/null +++ b/vue-full/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle.vue' diff --git a/vue-full/src/components/editor/ui/table-handle/table-handle.vue b/vue-full/src/components/editor/ui/table-handle/table-handle.vue new file mode 100644 index 0000000000..a9921a8f37 --- /dev/null +++ b/vue-full/src/components/editor/ui/table-handle/table-handle.vue @@ -0,0 +1,204 @@ + + + diff --git a/vue-full/src/components/editor/ui/tag-menu/index.ts b/vue-full/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..6cb07b1d1c --- /dev/null +++ b/vue-full/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu.vue' diff --git a/vue-full/src/components/editor/ui/tag-menu/tag-menu.vue b/vue-full/src/components/editor/ui/tag-menu/tag-menu.vue new file mode 100644 index 0000000000..a8928c53a9 --- /dev/null +++ b/vue-full/src/components/editor/ui/tag-menu/tag-menu.vue @@ -0,0 +1,59 @@ + + + diff --git a/vue-full/src/components/editor/ui/toolbar/index.ts b/vue-full/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-full/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-full/src/components/editor/ui/toolbar/toolbar.vue b/vue-full/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-full/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-full/src/components/editor/ui/user-menu/index.ts b/vue-full/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..29fde1b0b4 --- /dev/null +++ b/vue-full/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu.vue' diff --git a/vue-full/src/components/editor/ui/user-menu/user-menu.vue b/vue-full/src/components/editor/ui/user-menu/user-menu.vue new file mode 100644 index 0000000000..60b4c3131c --- /dev/null +++ b/vue-full/src/components/editor/ui/user-menu/user-menu.vue @@ -0,0 +1,74 @@ + + + diff --git a/vue-full/src/main.ts b/vue-full/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-full/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-full/tsconfig.app.json b/vue-full/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-full/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-full/tsconfig.json b/vue-full/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-full/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-full/tsconfig.node.json b/vue-full/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-full/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-full/vite.config.ts b/vue-full/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-full/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-gap-cursor/.gitignore b/vue-gap-cursor/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-gap-cursor/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-gap-cursor/README.md b/vue-gap-cursor/README.md new file mode 100644 index 0000000000..9a5bc280fb --- /dev/null +++ b/vue-gap-cursor/README.md @@ -0,0 +1,15 @@ +# vue-gap-cursor + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-gap-cursor) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-gap-cursor) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-gap-cursor vue-gap-cursor +cd vue-gap-cursor +npm install +npm run dev +``` diff --git a/vue-gap-cursor/index.html b/vue-gap-cursor/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-gap-cursor/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-gap-cursor/package.json b/vue-gap-cursor/package.json new file mode 100644 index 0000000000..a829a18ff3 --- /dev/null +++ b/vue-gap-cursor/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-gap-cursor", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-gap-cursor/src/App.vue b/vue-gap-cursor/src/App.vue new file mode 100644 index 0000000000..9ba97a0e0c --- /dev/null +++ b/vue-gap-cursor/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-gap-cursor/src/app.css b/vue-gap-cursor/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-gap-cursor/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-gap-cursor/src/components/editor/examples/gap-cursor/editor.vue b/vue-gap-cursor/src/components/editor/examples/gap-cursor/editor.vue new file mode 100644 index 0000000000..021cf9d82f --- /dev/null +++ b/vue-gap-cursor/src/components/editor/examples/gap-cursor/editor.vue @@ -0,0 +1,34 @@ + + + diff --git a/vue-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts b/vue-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts new file mode 100644 index 0000000000..599497170d --- /dev/null +++ b/vue-gap-cursor/src/components/editor/examples/gap-cursor/extension.ts @@ -0,0 +1,19 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineImage } from 'prosekit/extensions/image' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineGapCursor(), + defineImage(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-gap-cursor/src/components/editor/examples/gap-cursor/index.ts b/vue-gap-cursor/src/components/editor/examples/gap-cursor/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-gap-cursor/src/components/editor/examples/gap-cursor/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts b/vue-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts new file mode 100644 index 0000000000..e40ee2a83b --- /dev/null +++ b/vue-gap-cursor/src/components/editor/sample/sample-doc-gap-cursor.ts @@ -0,0 +1,28 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Click the gap between two images or press arrow keys to see the gap cursor between two images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/minimal/320x180/42', + }, + }, + ], +} diff --git a/vue-gap-cursor/src/main.ts b/vue-gap-cursor/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-gap-cursor/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-gap-cursor/tsconfig.app.json b/vue-gap-cursor/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-gap-cursor/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-gap-cursor/tsconfig.json b/vue-gap-cursor/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-gap-cursor/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-gap-cursor/tsconfig.node.json b/vue-gap-cursor/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-gap-cursor/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-gap-cursor/vite.config.ts b/vue-gap-cursor/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-gap-cursor/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-hard-break/.gitignore b/vue-hard-break/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-hard-break/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-hard-break/README.md b/vue-hard-break/README.md new file mode 100644 index 0000000000..00b5e0a802 --- /dev/null +++ b/vue-hard-break/README.md @@ -0,0 +1,15 @@ +# vue-hard-break + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-hard-break) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-hard-break) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-hard-break vue-hard-break +cd vue-hard-break +npm install +npm run dev +``` diff --git a/vue-hard-break/index.html b/vue-hard-break/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-hard-break/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-hard-break/package.json b/vue-hard-break/package.json new file mode 100644 index 0000000000..32b17e1763 --- /dev/null +++ b/vue-hard-break/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-hard-break", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-hard-break/src/App.vue b/vue-hard-break/src/App.vue new file mode 100644 index 0000000000..c7d9603a71 --- /dev/null +++ b/vue-hard-break/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-hard-break/src/app.css b/vue-hard-break/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-hard-break/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-hard-break/src/components/editor/examples/hard-break/editor.vue b/vue-hard-break/src/components/editor/examples/hard-break/editor.vue new file mode 100644 index 0000000000..89775668b2 --- /dev/null +++ b/vue-hard-break/src/components/editor/examples/hard-break/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-hard-break/src/components/editor/examples/hard-break/extension.ts b/vue-hard-break/src/components/editor/examples/hard-break/extension.ts new file mode 100644 index 0000000000..cad2881056 --- /dev/null +++ b/vue-hard-break/src/components/editor/examples/hard-break/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHardBreak } from 'prosekit/extensions/hard-break' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHardBreak(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-hard-break/src/components/editor/examples/hard-break/index.ts b/vue-hard-break/src/components/editor/examples/hard-break/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-hard-break/src/components/editor/examples/hard-break/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-hard-break/src/components/editor/examples/hard-break/toolbar.vue b/vue-hard-break/src/components/editor/examples/hard-break/toolbar.vue new file mode 100644 index 0000000000..400e6c2967 --- /dev/null +++ b/vue-hard-break/src/components/editor/examples/hard-break/toolbar.vue @@ -0,0 +1,33 @@ + + + diff --git a/vue-hard-break/src/components/editor/sample/sample-doc-hard-break.ts b/vue-hard-break/src/components/editor/sample/sample-doc-hard-break.ts new file mode 100644 index 0000000000..e1c9786b72 --- /dev/null +++ b/vue-hard-break/src/components/editor/sample/sample-doc-hard-break.ts @@ -0,0 +1,68 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: "O'er all the hilltops", + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Is quiet now,', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'In all the treetops', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hearest thou', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Hardly a breath;', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'The birds are asleep in the trees:', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Wait, soon like these', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'Thou too shalt rest.', + }, + { + type: 'hardBreak', + }, + ], + }, + ], +} diff --git a/vue-hard-break/src/components/editor/ui/button/button.vue b/vue-hard-break/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-hard-break/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-hard-break/src/components/editor/ui/button/index.ts b/vue-hard-break/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-hard-break/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-hard-break/src/main.ts b/vue-hard-break/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-hard-break/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-hard-break/tsconfig.app.json b/vue-hard-break/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-hard-break/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-hard-break/tsconfig.json b/vue-hard-break/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-hard-break/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-hard-break/tsconfig.node.json b/vue-hard-break/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-hard-break/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-hard-break/vite.config.ts b/vue-hard-break/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-hard-break/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-heading/.gitignore b/vue-heading/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-heading/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-heading/README.md b/vue-heading/README.md new file mode 100644 index 0000000000..d41728fca0 --- /dev/null +++ b/vue-heading/README.md @@ -0,0 +1,15 @@ +# vue-heading + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-heading) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-heading) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-heading vue-heading +cd vue-heading +npm install +npm run dev +``` diff --git a/vue-heading/index.html b/vue-heading/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-heading/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-heading/package.json b/vue-heading/package.json new file mode 100644 index 0000000000..ed80f16985 --- /dev/null +++ b/vue-heading/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-heading", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-heading/src/App.vue b/vue-heading/src/App.vue new file mode 100644 index 0000000000..9afe66706f --- /dev/null +++ b/vue-heading/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-heading/src/app.css b/vue-heading/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-heading/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-heading/src/components/editor/examples/heading/editor.vue b/vue-heading/src/components/editor/examples/heading/editor.vue new file mode 100644 index 0000000000..7a5f02b51a --- /dev/null +++ b/vue-heading/src/components/editor/examples/heading/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-heading/src/components/editor/examples/heading/extension.ts b/vue-heading/src/components/editor/examples/heading/extension.ts new file mode 100644 index 0000000000..e4f8e6ace0 --- /dev/null +++ b/vue-heading/src/components/editor/examples/heading/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHeading(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-heading/src/components/editor/examples/heading/index.ts b/vue-heading/src/components/editor/examples/heading/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-heading/src/components/editor/examples/heading/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-heading/src/components/editor/sample/sample-doc-heading.ts b/vue-heading/src/components/editor/sample/sample-doc-heading.ts new file mode 100644 index 0000000000..210497e633 --- /dev/null +++ b/vue-heading/src/components/editor/sample/sample-doc-heading.ts @@ -0,0 +1,23 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'H1' }], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'H2' }], + }, + { + type: 'heading', + attrs: { level: 3 }, + content: [{ type: 'text', text: 'H3' }], + }, + { type: 'paragraph', content: [] }, + ], +} diff --git a/vue-heading/src/components/editor/ui/button/button.vue b/vue-heading/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-heading/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-heading/src/components/editor/ui/button/index.ts b/vue-heading/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-heading/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-heading/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-heading/src/components/editor/ui/image-upload-popover/index.ts b/vue-heading/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-heading/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-heading/src/components/editor/ui/toolbar/index.ts b/vue-heading/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-heading/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-heading/src/components/editor/ui/toolbar/toolbar.vue b/vue-heading/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-heading/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-heading/src/main.ts b/vue-heading/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-heading/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-heading/tsconfig.app.json b/vue-heading/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-heading/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-heading/tsconfig.json b/vue-heading/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-heading/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-heading/tsconfig.node.json b/vue-heading/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-heading/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-heading/vite.config.ts b/vue-heading/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-heading/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-highlight/.gitignore b/vue-highlight/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-highlight/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-highlight/README.md b/vue-highlight/README.md new file mode 100644 index 0000000000..1d8b925785 --- /dev/null +++ b/vue-highlight/README.md @@ -0,0 +1,15 @@ +# vue-highlight + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-highlight) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-highlight) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-highlight vue-highlight +cd vue-highlight +npm install +npm run dev +``` diff --git a/vue-highlight/index.html b/vue-highlight/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-highlight/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-highlight/package.json b/vue-highlight/package.json new file mode 100644 index 0000000000..da7b437084 --- /dev/null +++ b/vue-highlight/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-highlight", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-highlight/src/App.vue b/vue-highlight/src/App.vue new file mode 100644 index 0000000000..1bea698fd7 --- /dev/null +++ b/vue-highlight/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-highlight/src/app.css b/vue-highlight/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-highlight/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-highlight/src/components/editor/examples/highlight/editor.vue b/vue-highlight/src/components/editor/examples/highlight/editor.vue new file mode 100644 index 0000000000..930156a17a --- /dev/null +++ b/vue-highlight/src/components/editor/examples/highlight/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-highlight/src/components/editor/examples/highlight/extension.ts b/vue-highlight/src/components/editor/examples/highlight/extension.ts new file mode 100644 index 0000000000..abc131c3be --- /dev/null +++ b/vue-highlight/src/components/editor/examples/highlight/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHighlight } from 'prosekit/extensions/highlight' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHighlight(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-highlight/src/components/editor/examples/highlight/index.ts b/vue-highlight/src/components/editor/examples/highlight/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-highlight/src/components/editor/examples/highlight/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-highlight/src/components/editor/examples/highlight/toolbar.vue b/vue-highlight/src/components/editor/examples/highlight/toolbar.vue new file mode 100644 index 0000000000..2e6d3c1310 --- /dev/null +++ b/vue-highlight/src/components/editor/examples/highlight/toolbar.vue @@ -0,0 +1,34 @@ + + + diff --git a/vue-highlight/src/components/editor/sample/sample-doc-highlight.ts b/vue-highlight/src/components/editor/sample/sample-doc-highlight.ts new file mode 100644 index 0000000000..0de1a1f7b2 --- /dev/null +++ b/vue-highlight/src/components/editor/sample/sample-doc-highlight.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'highlight', + }, + ], + text: 'This is highlighted text', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/vue-highlight/src/components/editor/ui/button/button.vue b/vue-highlight/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-highlight/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-highlight/src/components/editor/ui/button/index.ts b/vue-highlight/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-highlight/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-highlight/src/main.ts b/vue-highlight/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-highlight/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-highlight/tsconfig.app.json b/vue-highlight/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-highlight/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-highlight/tsconfig.json b/vue-highlight/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-highlight/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-highlight/tsconfig.node.json b/vue-highlight/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-highlight/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-highlight/vite.config.ts b/vue-highlight/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-highlight/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-horizontal-rule/.gitignore b/vue-horizontal-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-horizontal-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-horizontal-rule/README.md b/vue-horizontal-rule/README.md new file mode 100644 index 0000000000..074eb081e9 --- /dev/null +++ b/vue-horizontal-rule/README.md @@ -0,0 +1,15 @@ +# vue-horizontal-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-horizontal-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-horizontal-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-horizontal-rule vue-horizontal-rule +cd vue-horizontal-rule +npm install +npm run dev +``` diff --git a/vue-horizontal-rule/index.html b/vue-horizontal-rule/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-horizontal-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-horizontal-rule/package.json b/vue-horizontal-rule/package.json new file mode 100644 index 0000000000..adb7312241 --- /dev/null +++ b/vue-horizontal-rule/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-horizontal-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-horizontal-rule/src/App.vue b/vue-horizontal-rule/src/App.vue new file mode 100644 index 0000000000..805a365902 --- /dev/null +++ b/vue-horizontal-rule/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-horizontal-rule/src/app.css b/vue-horizontal-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-horizontal-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.vue b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.vue new file mode 100644 index 0000000000..7d4edcece6 --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/editor.vue @@ -0,0 +1,30 @@ + + + diff --git a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts new file mode 100644 index 0000000000..49b6121eeb --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineHorizontalRule } from 'prosekit/extensions/horizontal-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineHorizontalRule(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/examples/horizontal-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-horizontal-rule/src/components/editor/ui/button/button.vue b/vue-horizontal-rule/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-horizontal-rule/src/components/editor/ui/button/index.ts b/vue-horizontal-rule/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts b/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-horizontal-rule/src/components/editor/ui/toolbar/index.ts b/vue-horizontal-rule/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-horizontal-rule/src/components/editor/ui/toolbar/toolbar.vue b/vue-horizontal-rule/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-horizontal-rule/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-horizontal-rule/src/main.ts b/vue-horizontal-rule/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-horizontal-rule/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-horizontal-rule/tsconfig.app.json b/vue-horizontal-rule/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-horizontal-rule/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-horizontal-rule/tsconfig.json b/vue-horizontal-rule/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-horizontal-rule/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-horizontal-rule/tsconfig.node.json b/vue-horizontal-rule/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-horizontal-rule/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-horizontal-rule/vite.config.ts b/vue-horizontal-rule/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-horizontal-rule/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-image-view/.gitignore b/vue-image-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-image-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-image-view/README.md b/vue-image-view/README.md new file mode 100644 index 0000000000..d0391ce760 --- /dev/null +++ b/vue-image-view/README.md @@ -0,0 +1,15 @@ +# vue-image-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-image-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-image-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-image-view vue-image-view +cd vue-image-view +npm install +npm run dev +``` diff --git a/vue-image-view/index.html b/vue-image-view/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-image-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-image-view/package.json b/vue-image-view/package.json new file mode 100644 index 0000000000..eceb69d805 --- /dev/null +++ b/vue-image-view/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-image-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-image-view/src/App.vue b/vue-image-view/src/App.vue new file mode 100644 index 0000000000..047bb363a5 --- /dev/null +++ b/vue-image-view/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-image-view/src/app.css b/vue-image-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-image-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-image-view/src/components/editor/examples/image-view/editor.vue b/vue-image-view/src/components/editor/examples/image-view/editor.vue new file mode 100644 index 0000000000..63efeae16e --- /dev/null +++ b/vue-image-view/src/components/editor/examples/image-view/editor.vue @@ -0,0 +1,34 @@ + + + diff --git a/vue-image-view/src/components/editor/examples/image-view/extension.ts b/vue-image-view/src/components/editor/examples/image-view/extension.ts new file mode 100644 index 0000000000..a21febf634 --- /dev/null +++ b/vue-image-view/src/components/editor/examples/image-view/extension.ts @@ -0,0 +1,18 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineImageUploadHandler } from 'prosekit/extensions/image' + +import { sampleUploader } from '../../sample/sample-uploader' +import { defineImageView } from '../../ui/image-view' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineImageView(), + defineImageUploadHandler({ + uploader: sampleUploader, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-image-view/src/components/editor/examples/image-view/index.ts b/vue-image-view/src/components/editor/examples/image-view/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-image-view/src/components/editor/examples/image-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-image-view/src/components/editor/sample/sample-doc-image.ts b/vue-image-view/src/components/editor/sample/sample-doc-image.ts new file mode 100644 index 0000000000..c97628339d --- /dev/null +++ b/vue-image-view/src/components/editor/sample/sample-doc-image.ts @@ -0,0 +1,32 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Paste or drop an image to upload it.', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/white/200x200/1', + width: 160, + height: 160, + }, + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/yellow/640x360/42', + width: 240, + height: 135, + }, + }, + ], +} diff --git a/vue-image-view/src/components/editor/sample/sample-uploader.ts b/vue-image-view/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/vue-image-view/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/vue-image-view/src/components/editor/ui/image-view/image-view.vue b/vue-image-view/src/components/editor/ui/image-view/image-view.vue new file mode 100644 index 0000000000..a8beb8acd2 --- /dev/null +++ b/vue-image-view/src/components/editor/ui/image-view/image-view.vue @@ -0,0 +1,97 @@ + + + diff --git a/vue-image-view/src/components/editor/ui/image-view/index.ts b/vue-image-view/src/components/editor/ui/image-view/index.ts new file mode 100644 index 0000000000..960e2c64d6 --- /dev/null +++ b/vue-image-view/src/components/editor/ui/image-view/index.ts @@ -0,0 +1,11 @@ +import type { Extension } from 'prosekit/core' +import { defineVueNodeView, type VueNodeViewComponent } from 'prosekit/vue' + +import ImageView from './image-view.vue' + +export function defineImageView(): Extension { + return defineVueNodeView({ + name: 'image', + component: ImageView as VueNodeViewComponent, + }) +} diff --git a/vue-image-view/src/main.ts b/vue-image-view/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-image-view/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-image-view/tsconfig.app.json b/vue-image-view/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-image-view/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-image-view/tsconfig.json b/vue-image-view/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-image-view/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-image-view/tsconfig.node.json b/vue-image-view/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-image-view/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-image-view/vite.config.ts b/vue-image-view/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-image-view/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-inline-menu/.gitignore b/vue-inline-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-inline-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-inline-menu/README.md b/vue-inline-menu/README.md new file mode 100644 index 0000000000..13e5ba1650 --- /dev/null +++ b/vue-inline-menu/README.md @@ -0,0 +1,15 @@ +# vue-inline-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-inline-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-inline-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-inline-menu vue-inline-menu +cd vue-inline-menu +npm install +npm run dev +``` diff --git a/vue-inline-menu/index.html b/vue-inline-menu/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-inline-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-inline-menu/package.json b/vue-inline-menu/package.json new file mode 100644 index 0000000000..0b1c24511a --- /dev/null +++ b/vue-inline-menu/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-inline-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-inline-menu/src/App.vue b/vue-inline-menu/src/App.vue new file mode 100644 index 0000000000..4bc7cabf04 --- /dev/null +++ b/vue-inline-menu/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-inline-menu/src/app.css b/vue-inline-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-inline-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-inline-menu/src/components/editor/examples/inline-menu/editor.vue b/vue-inline-menu/src/components/editor/examples/inline-menu/editor.vue new file mode 100644 index 0000000000..35a0904198 --- /dev/null +++ b/vue-inline-menu/src/components/editor/examples/inline-menu/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-inline-menu/src/components/editor/examples/inline-menu/extension.ts b/vue-inline-menu/src/components/editor/examples/inline-menu/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/vue-inline-menu/src/components/editor/examples/inline-menu/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/vue-inline-menu/src/components/editor/examples/inline-menu/index.ts b/vue-inline-menu/src/components/editor/examples/inline-menu/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-inline-menu/src/components/editor/examples/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts b/vue-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts new file mode 100644 index 0000000000..62a5984cb0 --- /dev/null +++ b/vue-inline-menu/src/components/editor/sample/sample-doc-inline-menu.ts @@ -0,0 +1,33 @@ +import type { NodeJSON } from 'prosekit/core' + +const loremText = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Aliquet nec ullamcorper sit amet risus. Nam aliquam sem et tortor consequat id porta. Interdum posuere lorem ipsum dolor sit amet. Lectus sit amet est placerat in egestas erat. Egestas sed tempus urna et pharetra pharetra. Sit amet cursus sit amet dictum sit amet. Porttitor leo a diam sollicitudin. Tellus orci ac auctor augue. Tellus in hac habitasse platea dictumst vestibulum. At elementum eu facilisis sed odio morbi. Dolor magna eget est lorem ipsum. Et malesuada fames ac turpis egestas. Arcu risus quis varius quam quisque id diam. Purus viverra accumsan in nisl nisi scelerisque eu ultrices. Ut tortor pretium viverra suspendisse potenti nullam ac tortor vitae.' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'Try to select some text', + }, + ], + }, + ...Array.from({ length: 10 }, () => ({ + type: 'paragraph' as const, + content: [ + { + type: 'text' as const, + text: loremText, + }, + ], + })), + ], +} diff --git a/vue-inline-menu/src/components/editor/ui/button/button.vue b/vue-inline-menu/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-inline-menu/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-inline-menu/src/components/editor/ui/button/index.ts b/vue-inline-menu/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-inline-menu/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-inline-menu/src/components/editor/ui/inline-menu/index.ts b/vue-inline-menu/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8c72e460c8 --- /dev/null +++ b/vue-inline-menu/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-inline-menu/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-inline-menu/src/components/editor/ui/inline-menu/inline-menu.vue new file mode 100644 index 0000000000..cacb76b189 --- /dev/null +++ b/vue-inline-menu/src/components/editor/ui/inline-menu/inline-menu.vue @@ -0,0 +1,219 @@ + + + diff --git a/vue-inline-menu/src/main.ts b/vue-inline-menu/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-inline-menu/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-inline-menu/tsconfig.app.json b/vue-inline-menu/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-inline-menu/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-inline-menu/tsconfig.json b/vue-inline-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-inline-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-inline-menu/tsconfig.node.json b/vue-inline-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-inline-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-inline-menu/vite.config.ts b/vue-inline-menu/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-inline-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-italic/.gitignore b/vue-italic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-italic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-italic/README.md b/vue-italic/README.md new file mode 100644 index 0000000000..755e74cbbc --- /dev/null +++ b/vue-italic/README.md @@ -0,0 +1,15 @@ +# vue-italic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-italic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-italic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-italic vue-italic +cd vue-italic +npm install +npm run dev +``` diff --git a/vue-italic/index.html b/vue-italic/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-italic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-italic/package.json b/vue-italic/package.json new file mode 100644 index 0000000000..a6aaca4808 --- /dev/null +++ b/vue-italic/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-italic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-italic/src/App.vue b/vue-italic/src/App.vue new file mode 100644 index 0000000000..398832bc53 --- /dev/null +++ b/vue-italic/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-italic/src/app.css b/vue-italic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-italic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-italic/src/components/editor/examples/italic/editor.vue b/vue-italic/src/components/editor/examples/italic/editor.vue new file mode 100644 index 0000000000..db1429707f --- /dev/null +++ b/vue-italic/src/components/editor/examples/italic/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-italic/src/components/editor/examples/italic/extension.ts b/vue-italic/src/components/editor/examples/italic/extension.ts new file mode 100644 index 0000000000..a456b06aad --- /dev/null +++ b/vue-italic/src/components/editor/examples/italic/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineItalic(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-italic/src/components/editor/examples/italic/index.ts b/vue-italic/src/components/editor/examples/italic/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-italic/src/components/editor/examples/italic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-italic/src/components/editor/sample/sample-doc-italic.ts b/vue-italic/src/components/editor/sample/sample-doc-italic.ts new file mode 100644 index 0000000000..fb99415b2c --- /dev/null +++ b/vue-italic/src/components/editor/sample/sample-doc-italic.ts @@ -0,0 +1,44 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'This is italic too', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/vue-italic/src/components/editor/ui/button/button.vue b/vue-italic/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-italic/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-italic/src/components/editor/ui/button/index.ts b/vue-italic/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-italic/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-italic/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-italic/src/components/editor/ui/image-upload-popover/index.ts b/vue-italic/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-italic/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-italic/src/components/editor/ui/toolbar/index.ts b/vue-italic/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-italic/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-italic/src/components/editor/ui/toolbar/toolbar.vue b/vue-italic/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-italic/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-italic/src/main.ts b/vue-italic/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-italic/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-italic/tsconfig.app.json b/vue-italic/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-italic/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-italic/tsconfig.json b/vue-italic/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-italic/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-italic/tsconfig.node.json b/vue-italic/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-italic/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-italic/vite.config.ts b/vue-italic/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-italic/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-katex/.gitignore b/vue-katex/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-katex/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-katex/README.md b/vue-katex/README.md new file mode 100644 index 0000000000..b995c8e803 --- /dev/null +++ b/vue-katex/README.md @@ -0,0 +1,15 @@ +# vue-katex + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-katex) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-katex) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-katex vue-katex +cd vue-katex +npm install +npm run dev +``` diff --git a/vue-katex/index.html b/vue-katex/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-katex/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-katex/package.json b/vue-katex/package.json new file mode 100644 index 0000000000..f5b058cbd8 --- /dev/null +++ b/vue-katex/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-vue-katex", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-katex/src/App.vue b/vue-katex/src/App.vue new file mode 100644 index 0000000000..8d28f5c33a --- /dev/null +++ b/vue-katex/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-katex/src/app.css b/vue-katex/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-katex/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-katex/src/components/editor/examples/katex/editor.vue b/vue-katex/src/components/editor/examples/katex/editor.vue new file mode 100644 index 0000000000..7a5c4d69a9 --- /dev/null +++ b/vue-katex/src/components/editor/examples/katex/editor.vue @@ -0,0 +1,34 @@ + + + diff --git a/vue-katex/src/components/editor/examples/katex/extension.ts b/vue-katex/src/components/editor/examples/katex/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/vue-katex/src/components/editor/examples/katex/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-katex/src/components/editor/examples/katex/index.ts b/vue-katex/src/components/editor/examples/katex/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-katex/src/components/editor/examples/katex/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-katex/src/components/editor/sample/katex.ts b/vue-katex/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/vue-katex/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/vue-katex/src/components/editor/sample/sample-doc-tex.ts b/vue-katex/src/components/editor/sample/sample-doc-tex.ts new file mode 100644 index 0000000000..21ccf3e94e --- /dev/null +++ b/vue-katex/src/components/editor/sample/sample-doc-tex.ts @@ -0,0 +1,60 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Inline equations' }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text. Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$...$' }, + { type: 'text', text: ' to insert an inline equation.' }, + ], + }, + { + type: 'heading', + attrs: { level: 2 }, + content: [{ type: 'text', text: 'Block equations' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: 'The Gaussian integral:' }], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: 'Type ' }, + { type: 'text', marks: [{ type: 'code' }], text: '$$' }, + { + type: 'text', + text: ' in a new line and press Enter to create a block equation.', + }, + ], + }, + ], +} diff --git a/vue-katex/src/main.ts b/vue-katex/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-katex/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-katex/tsconfig.app.json b/vue-katex/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-katex/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-katex/tsconfig.json b/vue-katex/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-katex/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-katex/tsconfig.node.json b/vue-katex/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-katex/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-katex/vite.config.ts b/vue-katex/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-katex/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-keymap/.gitignore b/vue-keymap/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-keymap/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-keymap/README.md b/vue-keymap/README.md new file mode 100644 index 0000000000..9d4d310193 --- /dev/null +++ b/vue-keymap/README.md @@ -0,0 +1,15 @@ +# vue-keymap + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-keymap) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-keymap) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-keymap vue-keymap +cd vue-keymap +npm install +npm run dev +``` diff --git a/vue-keymap/index.html b/vue-keymap/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-keymap/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-keymap/package.json b/vue-keymap/package.json new file mode 100644 index 0000000000..96128af33c --- /dev/null +++ b/vue-keymap/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-keymap", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-keymap/src/App.vue b/vue-keymap/src/App.vue new file mode 100644 index 0000000000..bf4823a430 --- /dev/null +++ b/vue-keymap/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-keymap/src/app.css b/vue-keymap/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-keymap/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-keymap/src/components/editor/examples/keymap/editor.vue b/vue-keymap/src/components/editor/examples/keymap/editor.vue new file mode 100644 index 0000000000..2854f9624a --- /dev/null +++ b/vue-keymap/src/components/editor/examples/keymap/editor.vue @@ -0,0 +1,49 @@ + + + diff --git a/vue-keymap/src/components/editor/examples/keymap/extension.ts b/vue-keymap/src/components/editor/examples/keymap/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/vue-keymap/src/components/editor/examples/keymap/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/vue-keymap/src/components/editor/examples/keymap/index.ts b/vue-keymap/src/components/editor/examples/keymap/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-keymap/src/components/editor/examples/keymap/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-keymap/src/components/editor/examples/keymap/toolbar.vue b/vue-keymap/src/components/editor/examples/keymap/toolbar.vue new file mode 100644 index 0000000000..a84456c1f3 --- /dev/null +++ b/vue-keymap/src/components/editor/examples/keymap/toolbar.vue @@ -0,0 +1,38 @@ + + + diff --git a/vue-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts b/vue-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts new file mode 100644 index 0000000000..8aa8777560 --- /dev/null +++ b/vue-keymap/src/components/editor/examples/keymap/use-submit-keymap.ts @@ -0,0 +1,19 @@ +import type { Keymap } from 'prosekit/core' +import { useKeymap } from 'prosekit/vue' +import { computed, type Ref } from 'vue' + +export function useSubmitKeymap( + hotkey: Ref<'Shift-Enter' | 'Enter'>, + onSubmit: (hotkey: string) => void, +) { + const keymap = computed(() => { + return { + [hotkey.value]: () => { + onSubmit(hotkey.value) + return true + }, + } + }) + + useKeymap(keymap) +} diff --git a/vue-keymap/src/components/editor/ui/button/button.vue b/vue-keymap/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-keymap/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-keymap/src/components/editor/ui/button/index.ts b/vue-keymap/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-keymap/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-keymap/src/main.ts b/vue-keymap/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-keymap/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-keymap/tsconfig.app.json b/vue-keymap/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-keymap/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-keymap/tsconfig.json b/vue-keymap/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-keymap/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-keymap/tsconfig.node.json b/vue-keymap/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-keymap/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-keymap/vite.config.ts b/vue-keymap/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-keymap/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-link-mark-view/.gitignore b/vue-link-mark-view/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-link-mark-view/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-link-mark-view/README.md b/vue-link-mark-view/README.md new file mode 100644 index 0000000000..a3fc62d78b --- /dev/null +++ b/vue-link-mark-view/README.md @@ -0,0 +1,15 @@ +# vue-link-mark-view + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-link-mark-view) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-link-mark-view) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-link-mark-view vue-link-mark-view +cd vue-link-mark-view +npm install +npm run dev +``` diff --git a/vue-link-mark-view/index.html b/vue-link-mark-view/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-link-mark-view/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-link-mark-view/package.json b/vue-link-mark-view/package.json new file mode 100644 index 0000000000..ac288d419e --- /dev/null +++ b/vue-link-mark-view/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-link-mark-view", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-link-mark-view/src/App.vue b/vue-link-mark-view/src/App.vue new file mode 100644 index 0000000000..35cafd2c7b --- /dev/null +++ b/vue-link-mark-view/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-link-mark-view/src/app.css b/vue-link-mark-view/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-link-mark-view/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-link-mark-view/src/components/editor/examples/link-mark-view/editor.vue b/vue-link-mark-view/src/components/editor/examples/link-mark-view/editor.vue new file mode 100644 index 0000000000..c90a5b537d --- /dev/null +++ b/vue-link-mark-view/src/components/editor/examples/link-mark-view/editor.vue @@ -0,0 +1,34 @@ + + + diff --git a/vue-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts b/vue-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts new file mode 100644 index 0000000000..5e85a8f55b --- /dev/null +++ b/vue-link-mark-view/src/components/editor/examples/link-mark-view/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineVueMarkView, type VueMarkViewComponent } from 'prosekit/vue' + +import LinkView from './link-view.vue' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineVueMarkView({ + name: 'link', + component: LinkView as VueMarkViewComponent, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-link-mark-view/src/components/editor/examples/link-mark-view/index.ts b/vue-link-mark-view/src/components/editor/examples/link-mark-view/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-link-mark-view/src/components/editor/examples/link-mark-view/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-link-mark-view/src/components/editor/examples/link-mark-view/link-view.vue b/vue-link-mark-view/src/components/editor/examples/link-mark-view/link-view.vue new file mode 100644 index 0000000000..4353904d26 --- /dev/null +++ b/vue-link-mark-view/src/components/editor/examples/link-mark-view/link-view.vue @@ -0,0 +1,48 @@ + + + diff --git a/vue-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts b/vue-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts new file mode 100644 index 0000000000..57abd09dd6 --- /dev/null +++ b/vue-link-mark-view/src/components/editor/sample/sample-doc-link-mark-view.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is a link that changes color every second: ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/vue-link-mark-view/src/main.ts b/vue-link-mark-view/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-link-mark-view/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-link-mark-view/tsconfig.app.json b/vue-link-mark-view/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-link-mark-view/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-link-mark-view/tsconfig.json b/vue-link-mark-view/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-link-mark-view/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-link-mark-view/tsconfig.node.json b/vue-link-mark-view/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-link-mark-view/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-link-mark-view/vite.config.ts b/vue-link-mark-view/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-link-mark-view/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-link/.gitignore b/vue-link/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-link/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-link/README.md b/vue-link/README.md new file mode 100644 index 0000000000..dff3467791 --- /dev/null +++ b/vue-link/README.md @@ -0,0 +1,15 @@ +# vue-link + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-link) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-link) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-link vue-link +cd vue-link +npm install +npm run dev +``` diff --git a/vue-link/index.html b/vue-link/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-link/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-link/package.json b/vue-link/package.json new file mode 100644 index 0000000000..413e1629e3 --- /dev/null +++ b/vue-link/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-link", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-link/src/App.vue b/vue-link/src/App.vue new file mode 100644 index 0000000000..5fb5eba0eb --- /dev/null +++ b/vue-link/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-link/src/app.css b/vue-link/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-link/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-link/src/components/editor/examples/link/editor.vue b/vue-link/src/components/editor/examples/link/editor.vue new file mode 100644 index 0000000000..51213a7af0 --- /dev/null +++ b/vue-link/src/components/editor/examples/link/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-link/src/components/editor/examples/link/extension.ts b/vue-link/src/components/editor/examples/link/extension.ts new file mode 100644 index 0000000000..bf499147da --- /dev/null +++ b/vue-link/src/components/editor/examples/link/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLink } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-link/src/components/editor/examples/link/index.ts b/vue-link/src/components/editor/examples/link/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-link/src/components/editor/examples/link/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-link/src/components/editor/sample/sample-doc-link.ts b/vue-link/src/components/editor/sample/sample-doc-link.ts new file mode 100644 index 0000000000..726cf334fd --- /dev/null +++ b/vue-link/src/components/editor/sample/sample-doc-link.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here is an ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://www.example.com', + target: null, + rel: null, + }, + }, + ], + text: 'example link', + }, + ], + }, + ], +} diff --git a/vue-link/src/components/editor/ui/button/button.vue b/vue-link/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-link/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-link/src/components/editor/ui/button/index.ts b/vue-link/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-link/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-link/src/components/editor/ui/inline-menu/index.ts b/vue-link/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8c72e460c8 --- /dev/null +++ b/vue-link/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-link/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-link/src/components/editor/ui/inline-menu/inline-menu.vue new file mode 100644 index 0000000000..cacb76b189 --- /dev/null +++ b/vue-link/src/components/editor/ui/inline-menu/inline-menu.vue @@ -0,0 +1,219 @@ + + + diff --git a/vue-link/src/main.ts b/vue-link/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-link/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-link/tsconfig.app.json b/vue-link/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-link/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-link/tsconfig.json b/vue-link/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-link/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-link/tsconfig.node.json b/vue-link/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-link/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-link/vite.config.ts b/vue-link/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-link/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-list-custom-checkbox/.gitignore b/vue-list-custom-checkbox/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-list-custom-checkbox/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-list-custom-checkbox/README.md b/vue-list-custom-checkbox/README.md new file mode 100644 index 0000000000..2eba5804ac --- /dev/null +++ b/vue-list-custom-checkbox/README.md @@ -0,0 +1,15 @@ +# vue-list-custom-checkbox + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-list-custom-checkbox) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-list-custom-checkbox) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-list-custom-checkbox vue-list-custom-checkbox +cd vue-list-custom-checkbox +npm install +npm run dev +``` diff --git a/vue-list-custom-checkbox/index.html b/vue-list-custom-checkbox/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-list-custom-checkbox/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-list-custom-checkbox/package.json b/vue-list-custom-checkbox/package.json new file mode 100644 index 0000000000..969ffe88d8 --- /dev/null +++ b/vue-list-custom-checkbox/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-list-custom-checkbox", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-list-custom-checkbox/src/App.vue b/vue-list-custom-checkbox/src/App.vue new file mode 100644 index 0000000000..af9081cb9e --- /dev/null +++ b/vue-list-custom-checkbox/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-list-custom-checkbox/src/app.css b/vue-list-custom-checkbox/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-list-custom-checkbox/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css new file mode 100644 index 0000000000..ec631b72ad --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/custom-list.css @@ -0,0 +1,75 @@ +div[data-custom-list-css-enabled] + .ProseMirror + .prosemirror-flat-list[data-list-kind='task'] { + & > .list-marker label { + box-sizing: border-box; + display: flex; + position: relative; + left: calc(var(--spacing) * -0.5); + align-items: center; + cursor: pointer; + transition: transform 0.15s ease-in-out; + + &:hover { + transform: scale(1.1); + } + + &::after { + position: absolute; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + content: ''; + color: var(--color-white); + opacity: 0; + } + + /* https://api.iconify.design/lucide.css?icons=check */ + &::after { + display: inline-block; + background-color: currentColor; + -webkit-mask-image: var(--svg); + mask-image: var(--svg); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-size: 100% 100%; + mask-size: 100% 100%; + --svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); + } + + & input { + box-sizing: border-box; + appearance: none; + width: calc(var(--spacing) * 5); + height: calc(var(--spacing) * 5); + margin: 0; + border-width: 1px; + border-style: solid; + border-radius: var(--radius-md); + border-color: color-mix(in srgb, var(--color-gray-300) 50%, transparent); + box-shadow: var(--shadow-sm); + cursor: pointer; + transition: all 0.15s ease-in-out; + + &:hover { + box-shadow: var(--shadow-md); + } + + &:checked { + border-color: var(--color-red-500); + background-color: var(--color-red-500); + } + } + } + + &[data-list-checked] > .list-marker label { + &::after { + opacity: 1; + } + } + + &[data-list-checked] { + color: var(--color-gray-400); + text-decoration: line-through; + text-decoration-color: var(--color-gray-400); + } +} diff --git a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.vue b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.vue new file mode 100644 index 0000000000..0dc311c847 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/editor.vue @@ -0,0 +1,41 @@ + + + diff --git a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/examples/list-custom-checkbox/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts b/vue-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts new file mode 100644 index 0000000000..972611aed1 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/sample/sample-doc-list-custom-checkbox.ts @@ -0,0 +1,38 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Custom list checkbox design and strikethrough for completed tasks. Please check ', + }, + { type: 'text', text: 'custom-list.css', marks: [{ type: 'code' }] }, + { type: 'text', text: ' for the styles.' }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Completed Task' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Incomplete Task' }], + }, + ], + }, + ], +} diff --git a/vue-list-custom-checkbox/src/components/editor/ui/button/button.vue b/vue-list-custom-checkbox/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-list-custom-checkbox/src/components/editor/ui/button/index.ts b/vue-list-custom-checkbox/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts b/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts b/vue-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.vue b/vue-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-list-custom-checkbox/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-list-custom-checkbox/src/main.ts b/vue-list-custom-checkbox/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-list-custom-checkbox/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-list-custom-checkbox/tsconfig.app.json b/vue-list-custom-checkbox/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-list-custom-checkbox/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-list-custom-checkbox/tsconfig.json b/vue-list-custom-checkbox/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-list-custom-checkbox/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-list-custom-checkbox/tsconfig.node.json b/vue-list-custom-checkbox/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-list-custom-checkbox/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-list-custom-checkbox/vite.config.ts b/vue-list-custom-checkbox/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-list-custom-checkbox/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-list/.gitignore b/vue-list/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-list/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-list/README.md b/vue-list/README.md new file mode 100644 index 0000000000..ceeabfefab --- /dev/null +++ b/vue-list/README.md @@ -0,0 +1,15 @@ +# vue-list + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-list) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-list) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-list vue-list +cd vue-list +npm install +npm run dev +``` diff --git a/vue-list/index.html b/vue-list/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-list/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-list/package.json b/vue-list/package.json new file mode 100644 index 0000000000..2fb8f9cc6b --- /dev/null +++ b/vue-list/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-list", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-list/src/App.vue b/vue-list/src/App.vue new file mode 100644 index 0000000000..01a39b3560 --- /dev/null +++ b/vue-list/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-list/src/app.css b/vue-list/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-list/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-list/src/components/editor/examples/list/editor.vue b/vue-list/src/components/editor/examples/list/editor.vue new file mode 100644 index 0000000000..02d30c8015 --- /dev/null +++ b/vue-list/src/components/editor/examples/list/editor.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue-list/src/components/editor/examples/list/extension.ts b/vue-list/src/components/editor/examples/list/extension.ts new file mode 100644 index 0000000000..f66bae6ff7 --- /dev/null +++ b/vue-list/src/components/editor/examples/list/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineList } from 'prosekit/extensions/list' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineList(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-list/src/components/editor/examples/list/index.ts b/vue-list/src/components/editor/examples/list/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-list/src/components/editor/examples/list/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-list/src/components/editor/sample/sample-doc-list.ts b/vue-list/src/components/editor/sample/sample-doc-list.ts new file mode 100644 index 0000000000..091bc37185 --- /dev/null +++ b/vue-list/src/components/editor/sample/sample-doc-list.ts @@ -0,0 +1,47 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Bullet List' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: 'Ordered List' }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Task List ' }] }, + ], + }, + { + type: 'list', + attrs: { kind: 'toggle', collapsed: true }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Toggle List' }] }, + { + type: 'list', + attrs: { + kind: 'bullet', + }, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'Hidden' }] }, + ], + }, + ], + }, + ], +} diff --git a/vue-list/src/components/editor/ui/button/button.vue b/vue-list/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-list/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-list/src/components/editor/ui/button/index.ts b/vue-list/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-list/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-list/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-list/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-list/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-list/src/components/editor/ui/image-upload-popover/index.ts b/vue-list/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-list/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-list/src/components/editor/ui/toolbar/index.ts b/vue-list/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-list/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-list/src/components/editor/ui/toolbar/toolbar.vue b/vue-list/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-list/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-list/src/main.ts b/vue-list/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-list/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-list/tsconfig.app.json b/vue-list/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-list/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-list/tsconfig.json b/vue-list/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-list/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-list/tsconfig.node.json b/vue-list/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-list/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-list/vite.config.ts b/vue-list/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-list/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-loro/.gitignore b/vue-loro/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-loro/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-loro/README.md b/vue-loro/README.md new file mode 100644 index 0000000000..68c1425266 --- /dev/null +++ b/vue-loro/README.md @@ -0,0 +1,15 @@ +# vue-loro + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-loro) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-loro) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-loro vue-loro +cd vue-loro +npm install +npm run dev +``` diff --git a/vue-loro/index.html b/vue-loro/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-loro/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-loro/package.json b/vue-loro/package.json new file mode 100644 index 0000000000..c4a1832c8c --- /dev/null +++ b/vue-loro/package.json @@ -0,0 +1,30 @@ +{ + "name": "example-vue-loro", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "loro-crdt": "^1.12.1", + "loro-prosemirror": "^0.4.3", + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vite-plugin-wasm": "^3.6.0", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-loro/src/App.vue b/vue-loro/src/App.vue new file mode 100644 index 0000000000..17defcfc3e --- /dev/null +++ b/vue-loro/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-loro/src/app.css b/vue-loro/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-loro/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-loro/src/components/editor/examples/loro/editor-component.vue b/vue-loro/src/components/editor/examples/loro/editor-component.vue new file mode 100644 index 0000000000..906dbff4cb --- /dev/null +++ b/vue-loro/src/components/editor/examples/loro/editor-component.vue @@ -0,0 +1,37 @@ + + + diff --git a/vue-loro/src/components/editor/examples/loro/editor.vue b/vue-loro/src/components/editor/examples/loro/editor.vue new file mode 100644 index 0000000000..1699f8ae88 --- /dev/null +++ b/vue-loro/src/components/editor/examples/loro/editor.vue @@ -0,0 +1,56 @@ + + + diff --git a/vue-loro/src/components/editor/examples/loro/extension.ts b/vue-loro/src/components/editor/examples/loro/extension.ts new file mode 100644 index 0000000000..5a85c5e168 --- /dev/null +++ b/vue-loro/src/components/editor/examples/loro/extension.ts @@ -0,0 +1,47 @@ +import type { CursorAwareness, LoroDocType } from 'loro-prosemirror' +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineLoro } from 'prosekit/extensions/loro' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +export function defineExtension(doc: LoroDocType, awareness: CursorAwareness) { + return union([ + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineLoro({ doc, awareness }), + ]) +} + +export type EditorExtension = ReturnType diff --git a/vue-loro/src/components/editor/examples/loro/index.ts b/vue-loro/src/components/editor/examples/loro/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-loro/src/components/editor/examples/loro/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-loro/src/components/editor/ui/button/button.vue b/vue-loro/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-loro/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-loro/src/components/editor/ui/button/index.ts b/vue-loro/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-loro/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-loro/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-loro/src/components/editor/ui/image-upload-popover/index.ts b/vue-loro/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-loro/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-loro/src/components/editor/ui/toolbar/index.ts b/vue-loro/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-loro/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-loro/src/components/editor/ui/toolbar/toolbar.vue b/vue-loro/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-loro/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-loro/src/main.ts b/vue-loro/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-loro/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-loro/tsconfig.app.json b/vue-loro/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-loro/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-loro/tsconfig.json b/vue-loro/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-loro/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-loro/tsconfig.node.json b/vue-loro/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-loro/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-loro/vite.config.ts b/vue-loro/vite.config.ts new file mode 100644 index 0000000000..ffb2555728 --- /dev/null +++ b/vue-loro/vite.config.ts @@ -0,0 +1,9 @@ +import wasm from 'vite-plugin-wasm' +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [wasm(), vue(), tailwindcss()], +}) diff --git a/vue-mark-rule/.gitignore b/vue-mark-rule/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-mark-rule/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-mark-rule/README.md b/vue-mark-rule/README.md new file mode 100644 index 0000000000..5973b90538 --- /dev/null +++ b/vue-mark-rule/README.md @@ -0,0 +1,15 @@ +# vue-mark-rule + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-mark-rule) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-mark-rule) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-mark-rule vue-mark-rule +cd vue-mark-rule +npm install +npm run dev +``` diff --git a/vue-mark-rule/index.html b/vue-mark-rule/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-mark-rule/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-mark-rule/package.json b/vue-mark-rule/package.json new file mode 100644 index 0000000000..ec030ddc3e --- /dev/null +++ b/vue-mark-rule/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-mark-rule", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-mark-rule/src/App.vue b/vue-mark-rule/src/App.vue new file mode 100644 index 0000000000..2446156889 --- /dev/null +++ b/vue-mark-rule/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-mark-rule/src/app.css b/vue-mark-rule/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-mark-rule/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-mark-rule/src/components/editor/examples/mark-rule/editor.vue b/vue-mark-rule/src/components/editor/examples/mark-rule/editor.vue new file mode 100644 index 0000000000..d8707ded7c --- /dev/null +++ b/vue-mark-rule/src/components/editor/examples/mark-rule/editor.vue @@ -0,0 +1,27 @@ + + + diff --git a/vue-mark-rule/src/components/editor/examples/mark-rule/extension.ts b/vue-mark-rule/src/components/editor/examples/mark-rule/extension.ts new file mode 100644 index 0000000000..4a1de40783 --- /dev/null +++ b/vue-mark-rule/src/components/editor/examples/mark-rule/extension.ts @@ -0,0 +1,32 @@ +import { + defineBaseCommands, + defineBaseKeymap, + defineHistory, + union, +} from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineLinkMarkRule, defineLinkSpec } from 'prosekit/extensions/link' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { definePlaceholder } from 'prosekit/extensions/placeholder' +import { defineText } from 'prosekit/extensions/text' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' + +import { defineIssueLink } from './issue-link' + +export function defineExtension() { + return union( + defineDoc(), + defineText(), + defineParagraph(), + defineHistory(), + defineBaseKeymap(), + defineBaseCommands(), + defineVirtualSelection(), + defineLinkSpec(), + defineLinkMarkRule(), + definePlaceholder({ placeholder: 'Try typing #123' }), + defineIssueLink(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-mark-rule/src/components/editor/examples/mark-rule/index.ts b/vue-mark-rule/src/components/editor/examples/mark-rule/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-mark-rule/src/components/editor/examples/mark-rule/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts b/vue-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts new file mode 100644 index 0000000000..3840b5e53d --- /dev/null +++ b/vue-mark-rule/src/components/editor/examples/mark-rule/issue-link.ts @@ -0,0 +1,32 @@ +import { defineMarkSpec, union } from 'prosekit/core' +import { defineMarkRule } from 'prosekit/extensions/mark-rule' + +export function defineIssueLink() { + return union( + defineMarkSpec({ + name: 'issueLink', + inclusive: false, + attrs: { + issueNumber: {}, + }, + toDOM(node) { + const issueNumber = node.attrs.issueNumber as number + return [ + 'a', + { + href: `https://example.com/issues/${issueNumber}`, + title: `Issue #${issueNumber}`, + }, + 0, + ] + }, + }), + defineMarkRule({ + regex: /#(\d+)/g, + type: 'issueLink', + attrs: (match) => { + return { issueNumber: Number.parseInt(match[1] || '0') } + }, + }), + ) +} diff --git a/vue-mark-rule/src/main.ts b/vue-mark-rule/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-mark-rule/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-mark-rule/tsconfig.app.json b/vue-mark-rule/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-mark-rule/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-mark-rule/tsconfig.json b/vue-mark-rule/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-mark-rule/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-mark-rule/tsconfig.node.json b/vue-mark-rule/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-mark-rule/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-mark-rule/vite.config.ts b/vue-mark-rule/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-mark-rule/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-minimal/.gitignore b/vue-minimal/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-minimal/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-minimal/README.md b/vue-minimal/README.md new file mode 100644 index 0000000000..0a552ae9b9 --- /dev/null +++ b/vue-minimal/README.md @@ -0,0 +1,15 @@ +# vue-minimal + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-minimal) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-minimal) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-minimal vue-minimal +cd vue-minimal +npm install +npm run dev +``` diff --git a/vue-minimal/index.html b/vue-minimal/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-minimal/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-minimal/package.json b/vue-minimal/package.json new file mode 100644 index 0000000000..d909f51da6 --- /dev/null +++ b/vue-minimal/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-minimal", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-minimal/src/App.vue b/vue-minimal/src/App.vue new file mode 100644 index 0000000000..19ffd1d801 --- /dev/null +++ b/vue-minimal/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-minimal/src/app.css b/vue-minimal/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-minimal/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-minimal/src/components/editor/examples/minimal/editor.vue b/vue-minimal/src/components/editor/examples/minimal/editor.vue new file mode 100644 index 0000000000..145f522bd6 --- /dev/null +++ b/vue-minimal/src/components/editor/examples/minimal/editor.vue @@ -0,0 +1,20 @@ + + + diff --git a/vue-minimal/src/components/editor/examples/minimal/index.ts b/vue-minimal/src/components/editor/examples/minimal/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-minimal/src/components/editor/examples/minimal/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-minimal/src/main.ts b/vue-minimal/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-minimal/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-minimal/tsconfig.app.json b/vue-minimal/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-minimal/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-minimal/tsconfig.json b/vue-minimal/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-minimal/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-minimal/tsconfig.node.json b/vue-minimal/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-minimal/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-minimal/vite.config.ts b/vue-minimal/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-minimal/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-placeholder/.gitignore b/vue-placeholder/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-placeholder/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-placeholder/README.md b/vue-placeholder/README.md new file mode 100644 index 0000000000..16b679f5e4 --- /dev/null +++ b/vue-placeholder/README.md @@ -0,0 +1,15 @@ +# vue-placeholder + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-placeholder) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-placeholder) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-placeholder vue-placeholder +cd vue-placeholder +npm install +npm run dev +``` diff --git a/vue-placeholder/index.html b/vue-placeholder/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-placeholder/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-placeholder/package.json b/vue-placeholder/package.json new file mode 100644 index 0000000000..acbe27df66 --- /dev/null +++ b/vue-placeholder/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-placeholder", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-placeholder/src/App.vue b/vue-placeholder/src/App.vue new file mode 100644 index 0000000000..82d3e6c263 --- /dev/null +++ b/vue-placeholder/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-placeholder/src/app.css b/vue-placeholder/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-placeholder/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-placeholder/src/components/editor/examples/placeholder/editor.vue b/vue-placeholder/src/components/editor/examples/placeholder/editor.vue new file mode 100644 index 0000000000..dd57454b64 --- /dev/null +++ b/vue-placeholder/src/components/editor/examples/placeholder/editor.vue @@ -0,0 +1,37 @@ + + + diff --git a/vue-placeholder/src/components/editor/examples/placeholder/extension.ts b/vue-placeholder/src/components/editor/examples/placeholder/extension.ts new file mode 100644 index 0000000000..12d0ba26f4 --- /dev/null +++ b/vue-placeholder/src/components/editor/examples/placeholder/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Type something...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-placeholder/src/components/editor/examples/placeholder/index.ts b/vue-placeholder/src/components/editor/examples/placeholder/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-placeholder/src/components/editor/examples/placeholder/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-placeholder/src/main.ts b/vue-placeholder/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-placeholder/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-placeholder/tsconfig.app.json b/vue-placeholder/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-placeholder/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-placeholder/tsconfig.json b/vue-placeholder/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-placeholder/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-placeholder/tsconfig.node.json b/vue-placeholder/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-placeholder/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-placeholder/vite.config.ts b/vue-placeholder/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-placeholder/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-readonly/.gitignore b/vue-readonly/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-readonly/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-readonly/README.md b/vue-readonly/README.md new file mode 100644 index 0000000000..ae78f92eb8 --- /dev/null +++ b/vue-readonly/README.md @@ -0,0 +1,15 @@ +# vue-readonly + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-readonly) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-readonly) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-readonly vue-readonly +cd vue-readonly +npm install +npm run dev +``` diff --git a/vue-readonly/index.html b/vue-readonly/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-readonly/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-readonly/package.json b/vue-readonly/package.json new file mode 100644 index 0000000000..156aa3eabb --- /dev/null +++ b/vue-readonly/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-readonly", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-readonly/src/App.vue b/vue-readonly/src/App.vue new file mode 100644 index 0000000000..2f82ce1dd8 --- /dev/null +++ b/vue-readonly/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-readonly/src/app.css b/vue-readonly/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-readonly/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-readonly/src/components/editor/examples/readonly/editor.vue b/vue-readonly/src/components/editor/examples/readonly/editor.vue new file mode 100644 index 0000000000..7fb2c31a5a --- /dev/null +++ b/vue-readonly/src/components/editor/examples/readonly/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-readonly/src/components/editor/examples/readonly/extension.ts b/vue-readonly/src/components/editor/examples/readonly/extension.ts new file mode 100644 index 0000000000..15210b5dc0 --- /dev/null +++ b/vue-readonly/src/components/editor/examples/readonly/extension.ts @@ -0,0 +1,7 @@ +import { defineBasicExtension } from 'prosekit/basic' + +export function defineExtension() { + return defineBasicExtension() +} + +export type EditorExtension = ReturnType diff --git a/vue-readonly/src/components/editor/examples/readonly/index.ts b/vue-readonly/src/components/editor/examples/readonly/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-readonly/src/components/editor/examples/readonly/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-readonly/src/components/editor/examples/readonly/toolbar.vue b/vue-readonly/src/components/editor/examples/readonly/toolbar.vue new file mode 100644 index 0000000000..e2100bbe5b --- /dev/null +++ b/vue-readonly/src/components/editor/examples/readonly/toolbar.vue @@ -0,0 +1,17 @@ + + + diff --git a/vue-readonly/src/components/editor/examples/readonly/use-readonly.ts b/vue-readonly/src/components/editor/examples/readonly/use-readonly.ts new file mode 100644 index 0000000000..db678caef3 --- /dev/null +++ b/vue-readonly/src/components/editor/examples/readonly/use-readonly.ts @@ -0,0 +1,18 @@ +import { defineReadonly } from 'prosekit/extensions/readonly' +import { useExtension } from 'prosekit/vue' +import { computed, ref } from 'vue' + +export function useReadonly() { + const readonly = ref(true) + + const extension = computed(() => { + return readonly.value ? defineReadonly() : null + }) + useExtension(extension) + + function setReadonly(value: boolean) { + readonly.value = value + } + + return { readonly, setReadonly } +} diff --git a/vue-readonly/src/components/editor/sample/sample-doc-readonly.ts b/vue-readonly/src/components/editor/sample/sample-doc-readonly.ts new file mode 100644 index 0000000000..abd9e2c6ac --- /dev/null +++ b/vue-readonly/src/components/editor/sample/sample-doc-readonly.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'The content is readonly. Press the buttons above to toggle the readonly mode.', + }, + ], + }, + ], +} diff --git a/vue-readonly/src/components/editor/ui/button/button.vue b/vue-readonly/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-readonly/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-readonly/src/components/editor/ui/button/index.ts b/vue-readonly/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-readonly/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-readonly/src/main.ts b/vue-readonly/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-readonly/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-readonly/tsconfig.app.json b/vue-readonly/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-readonly/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-readonly/tsconfig.json b/vue-readonly/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-readonly/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-readonly/tsconfig.node.json b/vue-readonly/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-readonly/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-readonly/vite.config.ts b/vue-readonly/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-readonly/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-rtl/.gitignore b/vue-rtl/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-rtl/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-rtl/README.md b/vue-rtl/README.md new file mode 100644 index 0000000000..59f5f6f166 --- /dev/null +++ b/vue-rtl/README.md @@ -0,0 +1,15 @@ +# vue-rtl + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-rtl) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-rtl) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-rtl vue-rtl +cd vue-rtl +npm install +npm run dev +``` diff --git a/vue-rtl/index.html b/vue-rtl/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-rtl/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-rtl/package.json b/vue-rtl/package.json new file mode 100644 index 0000000000..1eb5863ec3 --- /dev/null +++ b/vue-rtl/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-rtl", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-rtl/src/App.vue b/vue-rtl/src/App.vue new file mode 100644 index 0000000000..ced37540ee --- /dev/null +++ b/vue-rtl/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-rtl/src/app.css b/vue-rtl/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-rtl/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-rtl/src/components/editor/examples/rtl/editor.vue b/vue-rtl/src/components/editor/examples/rtl/editor.vue new file mode 100644 index 0000000000..6161fc7ef8 --- /dev/null +++ b/vue-rtl/src/components/editor/examples/rtl/editor.vue @@ -0,0 +1,47 @@ + + + diff --git a/vue-rtl/src/components/editor/examples/rtl/index.ts b/vue-rtl/src/components/editor/examples/rtl/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-rtl/src/components/editor/examples/rtl/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-rtl/src/components/editor/sample/sample-doc-rtl.ts b/vue-rtl/src/components/editor/sample/sample-doc-rtl.ts new file mode 100644 index 0000000000..696e797724 --- /dev/null +++ b/vue-rtl/src/components/editor/sample/sample-doc-rtl.ts @@ -0,0 +1,187 @@ +import type { NodeJSON } from 'prosekit/core' + +const translation = { + Paragraph: 'فقرة', + 'Root list item': 'عنصر قائمة جذري', + 'Sub list item': 'عنصر قائمة فرعي', + 'Completed task': 'مهمة مكتملة', + 'Pending task': 'مهمة قيد الانتظار', + Quote: 'اقتباس', +} as const + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { level: 1 }, + content: [{ type: 'text', text: 'Right to Left' }], + }, + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Paragraph'] }], + }, + { + type: 'list', + attrs: { kind: 'bullet' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Root list item'] }], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'ordered' }, + content: [ + { + type: 'paragraph', + content: [{ type: 'text', text: translation['Sub list item'] }], + }, + { + type: 'list', + attrs: { kind: 'task', checked: true }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Completed task'] }, + ], + }, + ], + }, + { + type: 'list', + attrs: { kind: 'task', checked: false }, + content: [ + { + type: 'paragraph', + content: [ + { type: 'text', text: translation['Pending task'] }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'codeBlock', + attrs: { language: 'javascript' }, + content: [ + { + type: 'text', + text: 'hello world', + }, + ], + }, + + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B1' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C1' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B2' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C2' }] }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'A3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'B3' }] }, + ], + }, + { + type: 'tableCell', + attrs: {}, + content: [ + { type: 'paragraph', content: [{ type: 'text', text: 'C3' }] }, + ], + }, + ], + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: translation['Quote'], + }, + ], + }, + ], + }, + ], +} diff --git a/vue-rtl/src/components/editor/sample/sample-uploader.ts b/vue-rtl/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/vue-rtl/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/vue-rtl/src/components/editor/ui/block-handle/block-handle.vue b/vue-rtl/src/components/editor/ui/block-handle/block-handle.vue new file mode 100644 index 0000000000..ba06a1416a --- /dev/null +++ b/vue-rtl/src/components/editor/ui/block-handle/block-handle.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/block-handle/index.ts b/vue-rtl/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..2c33eb5726 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.vue' diff --git a/vue-rtl/src/components/editor/ui/button/button.vue b/vue-rtl/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/button/index.ts b/vue-rtl/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-rtl/src/components/editor/ui/drop-indicator/drop-indicator.vue b/vue-rtl/src/components/editor/ui/drop-indicator/drop-indicator.vue new file mode 100644 index 0000000000..cac51a8629 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/drop-indicator/drop-indicator.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/drop-indicator/index.ts b/vue-rtl/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..b455b1217b --- /dev/null +++ b/vue-rtl/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator.vue' diff --git a/vue-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/image-upload-popover/index.ts b/vue-rtl/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-rtl/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-rtl/src/components/editor/ui/inline-menu/index.ts b/vue-rtl/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8c72e460c8 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-rtl/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-rtl/src/components/editor/ui/inline-menu/inline-menu.vue new file mode 100644 index 0000000000..cacb76b189 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/inline-menu/inline-menu.vue @@ -0,0 +1,219 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/slash-menu/index.ts b/vue-rtl/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..32d71d61f5 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu.vue' diff --git a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.vue b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.vue new file mode 100644 index 0000000000..50fc5468fb --- /dev/null +++ b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-empty.vue @@ -0,0 +1,11 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-item.vue b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-item.vue new file mode 100644 index 0000000000..2d99363b45 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu-item.vue @@ -0,0 +1,24 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/slash-menu/slash-menu.vue b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu.vue new file mode 100644 index 0000000000..87090511e3 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/slash-menu/slash-menu.vue @@ -0,0 +1,106 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/table-handle/index.ts b/vue-rtl/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..0132b96b36 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle.vue' diff --git a/vue-rtl/src/components/editor/ui/table-handle/table-handle.vue b/vue-rtl/src/components/editor/ui/table-handle/table-handle.vue new file mode 100644 index 0000000000..a9921a8f37 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/table-handle/table-handle.vue @@ -0,0 +1,204 @@ + + + diff --git a/vue-rtl/src/components/editor/ui/toolbar/index.ts b/vue-rtl/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-rtl/src/components/editor/ui/toolbar/toolbar.vue b/vue-rtl/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-rtl/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-rtl/src/main.ts b/vue-rtl/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-rtl/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-rtl/tsconfig.app.json b/vue-rtl/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-rtl/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-rtl/tsconfig.json b/vue-rtl/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-rtl/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-rtl/tsconfig.node.json b/vue-rtl/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-rtl/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-rtl/vite.config.ts b/vue-rtl/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-rtl/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-save-html/.gitignore b/vue-save-html/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-save-html/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-save-html/README.md b/vue-save-html/README.md new file mode 100644 index 0000000000..35c0a143b2 --- /dev/null +++ b/vue-save-html/README.md @@ -0,0 +1,15 @@ +# vue-save-html + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-save-html) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-save-html) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-save-html vue-save-html +cd vue-save-html +npm install +npm run dev +``` diff --git a/vue-save-html/index.html b/vue-save-html/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-save-html/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-save-html/package.json b/vue-save-html/package.json new file mode 100644 index 0000000000..0efcf75897 --- /dev/null +++ b/vue-save-html/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-save-html", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-save-html/src/App.vue b/vue-save-html/src/App.vue new file mode 100644 index 0000000000..f815d77bde --- /dev/null +++ b/vue-save-html/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-save-html/src/app.css b/vue-save-html/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-save-html/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-save-html/src/components/editor/examples/save-html/editor.vue b/vue-save-html/src/components/editor/examples/save-html/editor.vue new file mode 100644 index 0000000000..972df7e21d --- /dev/null +++ b/vue-save-html/src/components/editor/examples/save-html/editor.vue @@ -0,0 +1,75 @@ + + + diff --git a/vue-save-html/src/components/editor/examples/save-html/index.ts b/vue-save-html/src/components/editor/examples/save-html/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-save-html/src/components/editor/examples/save-html/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-save-html/src/main.ts b/vue-save-html/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-save-html/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-save-html/tsconfig.app.json b/vue-save-html/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-save-html/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-save-html/tsconfig.json b/vue-save-html/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-save-html/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-save-html/tsconfig.node.json b/vue-save-html/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-save-html/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-save-html/vite.config.ts b/vue-save-html/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-save-html/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-save-json/.gitignore b/vue-save-json/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-save-json/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-save-json/README.md b/vue-save-json/README.md new file mode 100644 index 0000000000..a0b49b9baa --- /dev/null +++ b/vue-save-json/README.md @@ -0,0 +1,15 @@ +# vue-save-json + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-save-json) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-save-json) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-save-json vue-save-json +cd vue-save-json +npm install +npm run dev +``` diff --git a/vue-save-json/index.html b/vue-save-json/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-save-json/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-save-json/package.json b/vue-save-json/package.json new file mode 100644 index 0000000000..01e46e9bcc --- /dev/null +++ b/vue-save-json/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-save-json", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-save-json/src/App.vue b/vue-save-json/src/App.vue new file mode 100644 index 0000000000..6f603e75b3 --- /dev/null +++ b/vue-save-json/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-save-json/src/app.css b/vue-save-json/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-save-json/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-save-json/src/components/editor/examples/save-json/editor.vue b/vue-save-json/src/components/editor/examples/save-json/editor.vue new file mode 100644 index 0000000000..6e0ca4d065 --- /dev/null +++ b/vue-save-json/src/components/editor/examples/save-json/editor.vue @@ -0,0 +1,75 @@ + + + diff --git a/vue-save-json/src/components/editor/examples/save-json/index.ts b/vue-save-json/src/components/editor/examples/save-json/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-save-json/src/components/editor/examples/save-json/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-save-json/src/main.ts b/vue-save-json/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-save-json/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-save-json/tsconfig.app.json b/vue-save-json/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-save-json/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-save-json/tsconfig.json b/vue-save-json/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-save-json/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-save-json/tsconfig.node.json b/vue-save-json/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-save-json/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-save-json/vite.config.ts b/vue-save-json/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-save-json/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-save-markdown/.gitignore b/vue-save-markdown/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-save-markdown/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-save-markdown/README.md b/vue-save-markdown/README.md new file mode 100644 index 0000000000..16101d6f52 --- /dev/null +++ b/vue-save-markdown/README.md @@ -0,0 +1,15 @@ +# vue-save-markdown + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-save-markdown) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-save-markdown) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-save-markdown vue-save-markdown +cd vue-save-markdown +npm install +npm run dev +``` diff --git a/vue-save-markdown/index.html b/vue-save-markdown/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-save-markdown/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-save-markdown/package.json b/vue-save-markdown/package.json new file mode 100644 index 0000000000..676d8a9908 --- /dev/null +++ b/vue-save-markdown/package.json @@ -0,0 +1,34 @@ +{ + "name": "example-vue-save-markdown", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "rehype-parse": "^9.0.1", + "rehype-remark": "^10.0.1", + "remark-gfm": "^4.0.1", + "remark-html": "^16.0.1", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.5", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-save-markdown/src/App.vue b/vue-save-markdown/src/App.vue new file mode 100644 index 0000000000..0c747fdfbb --- /dev/null +++ b/vue-save-markdown/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-save-markdown/src/app.css b/vue-save-markdown/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-save-markdown/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-save-markdown/src/components/editor/examples/save-markdown/editor.vue b/vue-save-markdown/src/components/editor/examples/save-markdown/editor.vue new file mode 100644 index 0000000000..179ceda35b --- /dev/null +++ b/vue-save-markdown/src/components/editor/examples/save-markdown/editor.vue @@ -0,0 +1,79 @@ + + + diff --git a/vue-save-markdown/src/components/editor/examples/save-markdown/index.ts b/vue-save-markdown/src/components/editor/examples/save-markdown/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-save-markdown/src/components/editor/examples/save-markdown/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-save-markdown/src/components/editor/examples/save-markdown/markdown.ts b/vue-save-markdown/src/components/editor/examples/save-markdown/markdown.ts new file mode 100644 index 0000000000..3f930adad2 --- /dev/null +++ b/vue-save-markdown/src/components/editor/examples/save-markdown/markdown.ts @@ -0,0 +1,26 @@ +import rehypeParse from 'rehype-parse' +import rehypeRemark from 'rehype-remark' +import remarkGfm from 'remark-gfm' +import remarkHtml from 'remark-html' +import remarkParse from 'remark-parse' +import remarkStringify from 'remark-stringify' +import { unified } from 'unified' + +export function markdownFromHTML(html: string): string { + return unified() + .use(rehypeParse) + .use(rehypeRemark) + .use(remarkGfm) + .use(remarkStringify) + .processSync(html) + .toString() +} + +export function htmlFromMarkdown(markdown: string): string { + return unified() + .use(remarkParse) + .use(remarkGfm) + .use(remarkHtml) + .processSync(markdown) + .toString() +} diff --git a/vue-save-markdown/src/main.ts b/vue-save-markdown/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-save-markdown/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-save-markdown/tsconfig.app.json b/vue-save-markdown/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-save-markdown/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-save-markdown/tsconfig.json b/vue-save-markdown/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-save-markdown/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-save-markdown/tsconfig.node.json b/vue-save-markdown/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-save-markdown/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-save-markdown/vite.config.ts b/vue-save-markdown/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-save-markdown/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-search/.gitignore b/vue-search/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-search/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-search/README.md b/vue-search/README.md new file mode 100644 index 0000000000..876b739893 --- /dev/null +++ b/vue-search/README.md @@ -0,0 +1,15 @@ +# vue-search + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-search) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-search) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-search vue-search +cd vue-search +npm install +npm run dev +``` diff --git a/vue-search/index.html b/vue-search/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-search/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-search/package.json b/vue-search/package.json new file mode 100644 index 0000000000..bccc01fef5 --- /dev/null +++ b/vue-search/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-search", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-search/src/App.vue b/vue-search/src/App.vue new file mode 100644 index 0000000000..eae73be827 --- /dev/null +++ b/vue-search/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-search/src/app.css b/vue-search/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-search/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-search/src/components/editor/examples/search/editor.vue b/vue-search/src/components/editor/examples/search/editor.vue new file mode 100644 index 0000000000..8ef91f5a06 --- /dev/null +++ b/vue-search/src/components/editor/examples/search/editor.vue @@ -0,0 +1,40 @@ + + + diff --git a/vue-search/src/components/editor/examples/search/extension.ts b/vue-search/src/components/editor/examples/search/extension.ts new file mode 100644 index 0000000000..10ff13f614 --- /dev/null +++ b/vue-search/src/components/editor/examples/search/extension.ts @@ -0,0 +1,9 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineSearchCommands } from 'prosekit/extensions/search' + +export function defineExtension() { + return union(defineBasicExtension(), defineSearchCommands()) +} + +export type EditorExtension = ReturnType diff --git a/vue-search/src/components/editor/examples/search/index.ts b/vue-search/src/components/editor/examples/search/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-search/src/components/editor/examples/search/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-search/src/components/editor/sample/sample-doc-search.ts b/vue-search/src/components/editor/sample/sample-doc-search.ts new file mode 100644 index 0000000000..c8160cca2a --- /dev/null +++ b/vue-search/src/components/editor/sample/sample-doc-search.ts @@ -0,0 +1,79 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Baa, baa, black sheep,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Have you any wool?', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Yes, sir, yes, sir,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Three bags full;', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'One for the master,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the dame,', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'And one for the little boy', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Who lives down the lane.', + }, + ], + }, + ], +} diff --git a/vue-search/src/components/editor/ui/button/button.vue b/vue-search/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-search/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-search/src/components/editor/ui/button/index.ts b/vue-search/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-search/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-search/src/components/editor/ui/search/index.ts b/vue-search/src/components/editor/ui/search/index.ts new file mode 100644 index 0000000000..39f30055a6 --- /dev/null +++ b/vue-search/src/components/editor/ui/search/index.ts @@ -0,0 +1 @@ +export { default as Search } from './search.vue' diff --git a/vue-search/src/components/editor/ui/search/search.vue b/vue-search/src/components/editor/ui/search/search.vue new file mode 100644 index 0000000000..114dd3ec14 --- /dev/null +++ b/vue-search/src/components/editor/ui/search/search.vue @@ -0,0 +1,166 @@ + + + diff --git a/vue-search/src/main.ts b/vue-search/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-search/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-search/tsconfig.app.json b/vue-search/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-search/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-search/tsconfig.json b/vue-search/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-search/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-search/tsconfig.node.json b/vue-search/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-search/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-search/vite.config.ts b/vue-search/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-search/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-slash-menu/.gitignore b/vue-slash-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-slash-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-slash-menu/README.md b/vue-slash-menu/README.md new file mode 100644 index 0000000000..62105fa293 --- /dev/null +++ b/vue-slash-menu/README.md @@ -0,0 +1,15 @@ +# vue-slash-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-slash-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-slash-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-slash-menu vue-slash-menu +cd vue-slash-menu +npm install +npm run dev +``` diff --git a/vue-slash-menu/index.html b/vue-slash-menu/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-slash-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-slash-menu/package.json b/vue-slash-menu/package.json new file mode 100644 index 0000000000..35b5d2aef6 --- /dev/null +++ b/vue-slash-menu/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-slash-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-slash-menu/src/App.vue b/vue-slash-menu/src/App.vue new file mode 100644 index 0000000000..110f613175 --- /dev/null +++ b/vue-slash-menu/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-slash-menu/src/app.css b/vue-slash-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-slash-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-slash-menu/src/components/editor/examples/slash-menu/editor.vue b/vue-slash-menu/src/components/editor/examples/slash-menu/editor.vue new file mode 100644 index 0000000000..a9b813b64c --- /dev/null +++ b/vue-slash-menu/src/components/editor/examples/slash-menu/editor.vue @@ -0,0 +1,30 @@ + + + diff --git a/vue-slash-menu/src/components/editor/examples/slash-menu/extension.ts b/vue-slash-menu/src/components/editor/examples/slash-menu/extension.ts new file mode 100644 index 0000000000..0edda60136 --- /dev/null +++ b/vue-slash-menu/src/components/editor/examples/slash-menu/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ placeholder: 'Press / for commands...' }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-slash-menu/src/components/editor/examples/slash-menu/index.ts b/vue-slash-menu/src/components/editor/examples/slash-menu/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-slash-menu/src/components/editor/examples/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-slash-menu/src/components/editor/ui/slash-menu/index.ts b/vue-slash-menu/src/components/editor/ui/slash-menu/index.ts new file mode 100644 index 0000000000..32d71d61f5 --- /dev/null +++ b/vue-slash-menu/src/components/editor/ui/slash-menu/index.ts @@ -0,0 +1 @@ +export { default as SlashMenu } from './slash-menu.vue' diff --git a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.vue b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.vue new file mode 100644 index 0000000000..50fc5468fb --- /dev/null +++ b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-empty.vue @@ -0,0 +1,11 @@ + + + diff --git a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.vue b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.vue new file mode 100644 index 0000000000..2d99363b45 --- /dev/null +++ b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu-item.vue @@ -0,0 +1,24 @@ + + + diff --git a/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu.vue b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu.vue new file mode 100644 index 0000000000..87090511e3 --- /dev/null +++ b/vue-slash-menu/src/components/editor/ui/slash-menu/slash-menu.vue @@ -0,0 +1,106 @@ + + + diff --git a/vue-slash-menu/src/main.ts b/vue-slash-menu/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-slash-menu/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-slash-menu/tsconfig.app.json b/vue-slash-menu/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-slash-menu/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-slash-menu/tsconfig.json b/vue-slash-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-slash-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-slash-menu/tsconfig.node.json b/vue-slash-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-slash-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-slash-menu/vite.config.ts b/vue-slash-menu/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-slash-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-strike/.gitignore b/vue-strike/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-strike/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-strike/README.md b/vue-strike/README.md new file mode 100644 index 0000000000..469b22b1fe --- /dev/null +++ b/vue-strike/README.md @@ -0,0 +1,15 @@ +# vue-strike + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-strike) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-strike) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-strike vue-strike +cd vue-strike +npm install +npm run dev +``` diff --git a/vue-strike/index.html b/vue-strike/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-strike/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-strike/package.json b/vue-strike/package.json new file mode 100644 index 0000000000..32f16988af --- /dev/null +++ b/vue-strike/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-strike", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-strike/src/App.vue b/vue-strike/src/App.vue new file mode 100644 index 0000000000..66e622743e --- /dev/null +++ b/vue-strike/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-strike/src/app.css b/vue-strike/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-strike/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-strike/src/components/editor/examples/strike/editor.vue b/vue-strike/src/components/editor/examples/strike/editor.vue new file mode 100644 index 0000000000..c9dc28c615 --- /dev/null +++ b/vue-strike/src/components/editor/examples/strike/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-strike/src/components/editor/examples/strike/extension.ts b/vue-strike/src/components/editor/examples/strike/extension.ts new file mode 100644 index 0000000000..c013303ccc --- /dev/null +++ b/vue-strike/src/components/editor/examples/strike/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineStrike(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-strike/src/components/editor/examples/strike/index.ts b/vue-strike/src/components/editor/examples/strike/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-strike/src/components/editor/examples/strike/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-strike/src/components/editor/examples/strike/toolbar.vue b/vue-strike/src/components/editor/examples/strike/toolbar.vue new file mode 100644 index 0000000000..57d95ef7ab --- /dev/null +++ b/vue-strike/src/components/editor/examples/strike/toolbar.vue @@ -0,0 +1,34 @@ + + + diff --git a/vue-strike/src/components/editor/sample/sample-doc-strike.ts b/vue-strike/src/components/editor/sample/sample-doc-strike.ts new file mode 100644 index 0000000000..2e025e9b02 --- /dev/null +++ b/vue-strike/src/components/editor/sample/sample-doc-strike.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'This is strike', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/vue-strike/src/components/editor/ui/button/button.vue b/vue-strike/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-strike/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-strike/src/components/editor/ui/button/index.ts b/vue-strike/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-strike/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-strike/src/main.ts b/vue-strike/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-strike/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-strike/tsconfig.app.json b/vue-strike/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-strike/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-strike/tsconfig.json b/vue-strike/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-strike/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-strike/tsconfig.node.json b/vue-strike/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-strike/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-strike/vite.config.ts b/vue-strike/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-strike/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-sub-sup/.gitignore b/vue-sub-sup/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-sub-sup/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-sub-sup/README.md b/vue-sub-sup/README.md new file mode 100644 index 0000000000..16022e1ade --- /dev/null +++ b/vue-sub-sup/README.md @@ -0,0 +1,15 @@ +# vue-sub-sup + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-sub-sup) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-sub-sup) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-sub-sup vue-sub-sup +cd vue-sub-sup +npm install +npm run dev +``` diff --git a/vue-sub-sup/index.html b/vue-sub-sup/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-sub-sup/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-sub-sup/package.json b/vue-sub-sup/package.json new file mode 100644 index 0000000000..f7ab3a38f3 --- /dev/null +++ b/vue-sub-sup/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-sub-sup", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-sub-sup/src/App.vue b/vue-sub-sup/src/App.vue new file mode 100644 index 0000000000..a9316cfb1c --- /dev/null +++ b/vue-sub-sup/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-sub-sup/src/app.css b/vue-sub-sup/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-sub-sup/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-sub-sup/src/components/editor/examples/sub-sup/editor.vue b/vue-sub-sup/src/components/editor/examples/sub-sup/editor.vue new file mode 100644 index 0000000000..d45c5c2cef --- /dev/null +++ b/vue-sub-sup/src/components/editor/examples/sub-sup/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-sub-sup/src/components/editor/examples/sub-sup/extension.ts b/vue-sub-sup/src/components/editor/examples/sub-sup/extension.ts new file mode 100644 index 0000000000..bd67245f86 --- /dev/null +++ b/vue-sub-sup/src/components/editor/examples/sub-sup/extension.ts @@ -0,0 +1,32 @@ +import { canUseRegexLookbehind, defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineMarkInputRule } from 'prosekit/extensions/input-rule' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineSubscript } from 'prosekit/extensions/subscript' +import { defineSuperscript } from 'prosekit/extensions/superscript' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineSubscript(), + defineSuperscript(), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)~([^\s~]|[^\s~][^~]*[^\s~])~$/ + : /~([^\s~]|[^\s~][^~]*[^\s~])~$/, + type: 'subscript', + }), + defineMarkInputRule({ + regex: canUseRegexLookbehind() + ? /(?<=\s|^)\^([^\s^]|[^\s^][^^]*[^\s^])\^$/ + : /\^([^\s^]|[^\s^][^^]*[^\s^])\^$/, + type: 'superscript', + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-sub-sup/src/components/editor/examples/sub-sup/index.ts b/vue-sub-sup/src/components/editor/examples/sub-sup/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-sub-sup/src/components/editor/examples/sub-sup/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-sub-sup/src/components/editor/examples/sub-sup/toolbar.vue b/vue-sub-sup/src/components/editor/examples/sub-sup/toolbar.vue new file mode 100644 index 0000000000..0d610bdedd --- /dev/null +++ b/vue-sub-sup/src/components/editor/examples/sub-sup/toolbar.vue @@ -0,0 +1,46 @@ + + + diff --git a/vue-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts b/vue-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts new file mode 100644 index 0000000000..011be750dc --- /dev/null +++ b/vue-sub-sup/src/components/editor/sample/sample-doc-sub-sup.ts @@ -0,0 +1,42 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'H', + }, + { + type: 'text', + marks: [ + { + type: 'subscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: 'O is water. x', + }, + { + type: 'text', + marks: [ + { + type: 'superscript', + }, + ], + text: '2', + }, + { + type: 'text', + text: ' is a square.', + }, + ], + }, + ], +} diff --git a/vue-sub-sup/src/components/editor/ui/button/button.vue b/vue-sub-sup/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-sub-sup/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-sub-sup/src/components/editor/ui/button/index.ts b/vue-sub-sup/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-sub-sup/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-sub-sup/src/main.ts b/vue-sub-sup/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-sub-sup/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-sub-sup/tsconfig.app.json b/vue-sub-sup/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-sub-sup/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-sub-sup/tsconfig.json b/vue-sub-sup/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-sub-sup/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-sub-sup/tsconfig.node.json b/vue-sub-sup/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-sub-sup/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-sub-sup/vite.config.ts b/vue-sub-sup/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-sub-sup/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-table/.gitignore b/vue-table/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-table/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-table/README.md b/vue-table/README.md new file mode 100644 index 0000000000..f471ddcd4d --- /dev/null +++ b/vue-table/README.md @@ -0,0 +1,15 @@ +# vue-table + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-table) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-table) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-table vue-table +cd vue-table +npm install +npm run dev +``` diff --git a/vue-table/index.html b/vue-table/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-table/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-table/package.json b/vue-table/package.json new file mode 100644 index 0000000000..8e00b5d10e --- /dev/null +++ b/vue-table/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-table", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-table/src/App.vue b/vue-table/src/App.vue new file mode 100644 index 0000000000..9d24299530 --- /dev/null +++ b/vue-table/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-table/src/app.css b/vue-table/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-table/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-table/src/components/editor/examples/table/editor.vue b/vue-table/src/components/editor/examples/table/editor.vue new file mode 100644 index 0000000000..333bd4a269 --- /dev/null +++ b/vue-table/src/components/editor/examples/table/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-table/src/components/editor/examples/table/extension.ts b/vue-table/src/components/editor/examples/table/extension.ts new file mode 100644 index 0000000000..ee7b142041 --- /dev/null +++ b/vue-table/src/components/editor/examples/table/extension.ts @@ -0,0 +1,20 @@ +import { defineBaseKeymap, defineHistory, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineGapCursor } from 'prosekit/extensions/gap-cursor' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineTable(), + defineHistory(), + defineGapCursor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-table/src/components/editor/examples/table/index.ts b/vue-table/src/components/editor/examples/table/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-table/src/components/editor/examples/table/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-table/src/components/editor/sample/sample-doc-table.ts b/vue-table/src/components/editor/sample/sample-doc-table.ts new file mode 100644 index 0000000000..c737121672 --- /dev/null +++ b/vue-table/src/components/editor/sample/sample-doc-table.ts @@ -0,0 +1,174 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D1', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'A2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'B2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'C2', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'D2', + }, + ], + }, + ], + }, + ], + }, + ], + }, + ], +} diff --git a/vue-table/src/components/editor/ui/table-handle/index.ts b/vue-table/src/components/editor/ui/table-handle/index.ts new file mode 100644 index 0000000000..0132b96b36 --- /dev/null +++ b/vue-table/src/components/editor/ui/table-handle/index.ts @@ -0,0 +1 @@ +export { default as TableHandle } from './table-handle.vue' diff --git a/vue-table/src/components/editor/ui/table-handle/table-handle.vue b/vue-table/src/components/editor/ui/table-handle/table-handle.vue new file mode 100644 index 0000000000..a9921a8f37 --- /dev/null +++ b/vue-table/src/components/editor/ui/table-handle/table-handle.vue @@ -0,0 +1,204 @@ + + + diff --git a/vue-table/src/main.ts b/vue-table/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-table/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-table/tsconfig.app.json b/vue-table/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-table/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-table/tsconfig.json b/vue-table/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-table/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-table/tsconfig.node.json b/vue-table/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-table/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-table/vite.config.ts b/vue-table/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-table/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-text-align/.gitignore b/vue-text-align/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-text-align/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-text-align/README.md b/vue-text-align/README.md new file mode 100644 index 0000000000..87cba2c361 --- /dev/null +++ b/vue-text-align/README.md @@ -0,0 +1,15 @@ +# vue-text-align + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-text-align) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-text-align) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-text-align vue-text-align +cd vue-text-align +npm install +npm run dev +``` diff --git a/vue-text-align/index.html b/vue-text-align/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-text-align/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-text-align/package.json b/vue-text-align/package.json new file mode 100644 index 0000000000..38fbfebf9e --- /dev/null +++ b/vue-text-align/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-text-align", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-text-align/src/App.vue b/vue-text-align/src/App.vue new file mode 100644 index 0000000000..f4c3f7bd20 --- /dev/null +++ b/vue-text-align/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-text-align/src/app.css b/vue-text-align/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-text-align/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-text-align/src/components/editor/examples/text-align/editor.vue b/vue-text-align/src/components/editor/examples/text-align/editor.vue new file mode 100644 index 0000000000..8659570703 --- /dev/null +++ b/vue-text-align/src/components/editor/examples/text-align/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-text-align/src/components/editor/examples/text-align/extension.ts b/vue-text-align/src/components/editor/examples/text-align/extension.ts new file mode 100644 index 0000000000..f1ae44dc7c --- /dev/null +++ b/vue-text-align/src/components/editor/examples/text-align/extension.ts @@ -0,0 +1,12 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineTextAlign } from 'prosekit/extensions/text-align' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextAlign({ types: ['paragraph', 'heading'] }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-text-align/src/components/editor/examples/text-align/index.ts b/vue-text-align/src/components/editor/examples/text-align/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-text-align/src/components/editor/examples/text-align/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-text-align/src/components/editor/examples/text-align/toolbar.vue b/vue-text-align/src/components/editor/examples/text-align/toolbar.vue new file mode 100644 index 0000000000..d68e9afb13 --- /dev/null +++ b/vue-text-align/src/components/editor/examples/text-align/toolbar.vue @@ -0,0 +1,80 @@ + + + diff --git a/vue-text-align/src/components/editor/sample/sample-doc-text-align.ts b/vue-text-align/src/components/editor/sample/sample-doc-text-align.ts new file mode 100644 index 0000000000..0724cea4f7 --- /dev/null +++ b/vue-text-align/src/components/editor/sample/sample-doc-text-align.ts @@ -0,0 +1,56 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Heading', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'left', + }, + content: [ + { + type: 'text', + text: 'First paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'center', + }, + content: [ + { + type: 'text', + text: 'Second paragraph', + }, + ], + }, + { + type: 'paragraph', + attrs: { + textAlign: 'right', + }, + content: [ + { + type: 'text', + text: 'Third paragraph', + }, + ], + }, + ], +} diff --git a/vue-text-align/src/components/editor/ui/button/button.vue b/vue-text-align/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-text-align/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-text-align/src/components/editor/ui/button/index.ts b/vue-text-align/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-text-align/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-text-align/src/main.ts b/vue-text-align/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-text-align/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-text-align/tsconfig.app.json b/vue-text-align/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-text-align/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-text-align/tsconfig.json b/vue-text-align/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-text-align/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-text-align/tsconfig.node.json b/vue-text-align/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-text-align/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-text-align/vite.config.ts b/vue-text-align/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-text-align/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-text-color/.gitignore b/vue-text-color/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-text-color/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-text-color/README.md b/vue-text-color/README.md new file mode 100644 index 0000000000..4576c5b97b --- /dev/null +++ b/vue-text-color/README.md @@ -0,0 +1,15 @@ +# vue-text-color + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-text-color) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-text-color) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-text-color vue-text-color +cd vue-text-color +npm install +npm run dev +``` diff --git a/vue-text-color/index.html b/vue-text-color/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-text-color/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-text-color/package.json b/vue-text-color/package.json new file mode 100644 index 0000000000..47722898a2 --- /dev/null +++ b/vue-text-color/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-text-color", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-text-color/src/App.vue b/vue-text-color/src/App.vue new file mode 100644 index 0000000000..a2131cecee --- /dev/null +++ b/vue-text-color/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-text-color/src/app.css b/vue-text-color/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-text-color/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-text-color/src/components/editor/examples/text-color/editor.vue b/vue-text-color/src/components/editor/examples/text-color/editor.vue new file mode 100644 index 0000000000..d5feed6f7d --- /dev/null +++ b/vue-text-color/src/components/editor/examples/text-color/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-text-color/src/components/editor/examples/text-color/extension.ts b/vue-text-color/src/components/editor/examples/text-color/extension.ts new file mode 100644 index 0000000000..d35d9d5c22 --- /dev/null +++ b/vue-text-color/src/components/editor/examples/text-color/extension.ts @@ -0,0 +1,14 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineBackgroundColor } from 'prosekit/extensions/background-color' +import { defineTextColor } from 'prosekit/extensions/text-color' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineTextColor(), + defineBackgroundColor(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-text-color/src/components/editor/examples/text-color/index.ts b/vue-text-color/src/components/editor/examples/text-color/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-text-color/src/components/editor/examples/text-color/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-text-color/src/components/editor/examples/text-color/inline-menu.vue b/vue-text-color/src/components/editor/examples/text-color/inline-menu.vue new file mode 100644 index 0000000000..41660b3614 --- /dev/null +++ b/vue-text-color/src/components/editor/examples/text-color/inline-menu.vue @@ -0,0 +1,142 @@ + + + diff --git a/vue-text-color/src/components/editor/sample/sample-doc-text-color.ts b/vue-text-color/src/components/editor/sample/sample-doc-text-color.ts new file mode 100644 index 0000000000..a4efe4308d --- /dev/null +++ b/vue-text-color/src/components/editor/sample/sample-doc-text-color.ts @@ -0,0 +1,120 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#ef4444', + }, + }, + ], + text: 'Select', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#f97316', + }, + }, + ], + text: 'some', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#eab308', + }, + }, + ], + text: 'text', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#22c55e', + }, + }, + ], + text: 'to', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#3b82f6', + }, + }, + ], + text: 'change', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#6366f1', + }, + }, + ], + text: 'the', + }, + { + type: 'text', + text: ' ', + }, + { + type: 'text', + marks: [ + { + type: 'textColor', + attrs: { + color: '#a855f7', + }, + }, + ], + text: 'color', + }, + ], + }, + ], +} diff --git a/vue-text-color/src/components/editor/ui/button/button.vue b/vue-text-color/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-text-color/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-text-color/src/components/editor/ui/button/index.ts b/vue-text-color/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-text-color/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-text-color/src/main.ts b/vue-text-color/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-text-color/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-text-color/tsconfig.app.json b/vue-text-color/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-text-color/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-text-color/tsconfig.json b/vue-text-color/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-text-color/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-text-color/tsconfig.node.json b/vue-text-color/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-text-color/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-text-color/vite.config.ts b/vue-text-color/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-text-color/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-toolbar/.gitignore b/vue-toolbar/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-toolbar/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-toolbar/README.md b/vue-toolbar/README.md new file mode 100644 index 0000000000..801b68f6d0 --- /dev/null +++ b/vue-toolbar/README.md @@ -0,0 +1,15 @@ +# vue-toolbar + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-toolbar) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-toolbar) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-toolbar vue-toolbar +cd vue-toolbar +npm install +npm run dev +``` diff --git a/vue-toolbar/index.html b/vue-toolbar/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-toolbar/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-toolbar/package.json b/vue-toolbar/package.json new file mode 100644 index 0000000000..ab491eee0f --- /dev/null +++ b/vue-toolbar/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-toolbar", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-toolbar/src/App.vue b/vue-toolbar/src/App.vue new file mode 100644 index 0000000000..f76a007d30 --- /dev/null +++ b/vue-toolbar/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-toolbar/src/app.css b/vue-toolbar/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-toolbar/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-toolbar/src/components/editor/examples/toolbar/editor.vue b/vue-toolbar/src/components/editor/examples/toolbar/editor.vue new file mode 100644 index 0000000000..580cc4ec8f --- /dev/null +++ b/vue-toolbar/src/components/editor/examples/toolbar/editor.vue @@ -0,0 +1,31 @@ + + + diff --git a/vue-toolbar/src/components/editor/examples/toolbar/extension.ts b/vue-toolbar/src/components/editor/examples/toolbar/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/vue-toolbar/src/components/editor/examples/toolbar/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/vue-toolbar/src/components/editor/examples/toolbar/index.ts b/vue-toolbar/src/components/editor/examples/toolbar/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-toolbar/src/components/editor/examples/toolbar/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-toolbar/src/components/editor/sample/sample-uploader.ts b/vue-toolbar/src/components/editor/sample/sample-uploader.ts new file mode 100644 index 0000000000..8e86d92105 --- /dev/null +++ b/vue-toolbar/src/components/editor/sample/sample-uploader.ts @@ -0,0 +1,54 @@ +import type { Uploader } from 'prosekit/extensions/file' + +/** + * Uploads the given file to https://tmpfiles.org/ and returns the URL of the + * uploaded file. + * + * This function is only for demonstration purposes. All uploaded files will be + * deleted by the server after 1 hour. + */ +export const sampleUploader: Uploader = ({ + file, + onProgress, +}): Promise => { + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest() + const formData = new FormData() + formData.append('file', file) + + xhr.upload.addEventListener('progress', (event) => { + if (event.lengthComputable) { + onProgress({ + loaded: event.loaded, + total: event.total, + }) + } + }) + + xhr.addEventListener('load', () => { + if (xhr.status === 200) { + try { + const json = JSON.parse(xhr.responseText) as { data: { url: string } } + const url: string = json.data.url.replace( + 'tmpfiles.org/', + 'tmpfiles.org/dl/', + ) + + // Simulate a larger delay + setTimeout(() => resolve(url), 1000) + } catch (error) { + reject(new Error('Failed to parse response', { cause: error })) + } + } else { + reject(new Error(`Upload failed with status ${xhr.status}`)) + } + }) + + xhr.addEventListener('error', () => { + reject(new Error('Upload failed')) + }) + + xhr.open('POST', 'https://tmpfiles.org/api/v1/upload', true) + xhr.send(formData) + }) +} diff --git a/vue-toolbar/src/components/editor/ui/button/button.vue b/vue-toolbar/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-toolbar/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-toolbar/src/components/editor/ui/button/index.ts b/vue-toolbar/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-toolbar/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-toolbar/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-toolbar/src/components/editor/ui/image-upload-popover/index.ts b/vue-toolbar/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-toolbar/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-toolbar/src/components/editor/ui/toolbar/index.ts b/vue-toolbar/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-toolbar/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-toolbar/src/components/editor/ui/toolbar/toolbar.vue b/vue-toolbar/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-toolbar/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-toolbar/src/main.ts b/vue-toolbar/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-toolbar/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-toolbar/tsconfig.app.json b/vue-toolbar/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-toolbar/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-toolbar/tsconfig.json b/vue-toolbar/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-toolbar/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-toolbar/tsconfig.node.json b/vue-toolbar/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-toolbar/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-toolbar/vite.config.ts b/vue-toolbar/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-toolbar/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-tweet/.gitignore b/vue-tweet/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-tweet/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-tweet/README.md b/vue-tweet/README.md new file mode 100644 index 0000000000..7381d9a7d9 --- /dev/null +++ b/vue-tweet/README.md @@ -0,0 +1,15 @@ +# vue-tweet + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-tweet) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-tweet) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-tweet vue-tweet +cd vue-tweet +npm install +npm run dev +``` diff --git a/vue-tweet/index.html b/vue-tweet/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-tweet/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-tweet/package.json b/vue-tweet/package.json new file mode 100644 index 0000000000..8aa7b835df --- /dev/null +++ b/vue-tweet/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-vue-tweet", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34", + "vue-tweet": "^2.4.0" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-tweet/src/App.vue b/vue-tweet/src/App.vue new file mode 100644 index 0000000000..8516fa911d --- /dev/null +++ b/vue-tweet/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-tweet/src/app.css b/vue-tweet/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-tweet/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-tweet/src/components/editor/examples/tweet/editor.vue b/vue-tweet/src/components/editor/examples/tweet/editor.vue new file mode 100644 index 0000000000..1a2cf8bd2b --- /dev/null +++ b/vue-tweet/src/components/editor/examples/tweet/editor.vue @@ -0,0 +1,59 @@ + + + diff --git a/vue-tweet/src/components/editor/examples/tweet/extension.ts b/vue-tweet/src/components/editor/examples/tweet/extension.ts new file mode 100644 index 0000000000..ec730c0899 --- /dev/null +++ b/vue-tweet/src/components/editor/examples/tweet/extension.ts @@ -0,0 +1,43 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { defineNodeSpec, union } from 'prosekit/core' + +function defineTweetSpec() { + return defineNodeSpec({ + name: 'tweet', + group: 'block', + attrs: { + tweetId: { default: null }, + }, + parseDOM: [ + { + tag: 'iframe[src^="https://platform.twitter.com/embed/Tweet.html"]', + getAttrs: (node) => { + const src = node.getAttribute('src') + const match = src?.match(/id=([^&]+)/) + return { + tweetId: match?.[1] ?? null, + } + }, + }, + ], + toDOM: (node) => { + return [ + 'iframe', + { + src: `https://platform.twitter.com/embed/Tweet.html?id=${node.attrs.tweetId}&theme=dark`, + style: 'height: 300px', + }, + ] + }, + }) +} + +function defineTweet() { + return union(defineTweetSpec()) +} + +export function defineExtension() { + return union(defineBasicExtension(), defineTweet()) +} + +export type EditorExtension = ReturnType diff --git a/vue-tweet/src/components/editor/examples/tweet/index.ts b/vue-tweet/src/components/editor/examples/tweet/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-tweet/src/components/editor/examples/tweet/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-tweet/src/components/editor/examples/tweet/method-select.vue b/vue-tweet/src/components/editor/examples/tweet/method-select.vue new file mode 100644 index 0000000000..2c563692b1 --- /dev/null +++ b/vue-tweet/src/components/editor/examples/tweet/method-select.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-tweet/src/components/editor/examples/tweet/tweet-view.vue b/vue-tweet/src/components/editor/examples/tweet/tweet-view.vue new file mode 100644 index 0000000000..b306e5feeb --- /dev/null +++ b/vue-tweet/src/components/editor/examples/tweet/tweet-view.vue @@ -0,0 +1,28 @@ + + + diff --git a/vue-tweet/src/components/editor/sample/sample-doc-tweet.ts b/vue-tweet/src/components/editor/sample/sample-doc-tweet.ts new file mode 100644 index 0000000000..f0c0e6ca60 --- /dev/null +++ b/vue-tweet/src/components/editor/sample/sample-doc-tweet.ts @@ -0,0 +1,22 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Render a tweet in your document', + }, + ], + }, + { + type: 'tweet', + attrs: { + tweetId: '20', + }, + }, + ], +} diff --git a/vue-tweet/src/main.ts b/vue-tweet/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-tweet/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-tweet/tsconfig.app.json b/vue-tweet/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-tweet/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-tweet/tsconfig.json b/vue-tweet/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-tweet/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-tweet/tsconfig.node.json b/vue-tweet/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-tweet/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-tweet/vite.config.ts b/vue-tweet/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-tweet/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-typography/.gitignore b/vue-typography/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-typography/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-typography/README.md b/vue-typography/README.md new file mode 100644 index 0000000000..0e7791cd16 --- /dev/null +++ b/vue-typography/README.md @@ -0,0 +1,15 @@ +# vue-typography + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-typography) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-typography) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-typography vue-typography +cd vue-typography +npm install +npm run dev +``` diff --git a/vue-typography/index.html b/vue-typography/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-typography/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-typography/package.json b/vue-typography/package.json new file mode 100644 index 0000000000..60d26ae9b7 --- /dev/null +++ b/vue-typography/package.json @@ -0,0 +1,28 @@ +{ + "name": "example-vue-typography", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "katex": "^0.16.47", + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-typography/src/App.vue b/vue-typography/src/App.vue new file mode 100644 index 0000000000..9d017ca508 --- /dev/null +++ b/vue-typography/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-typography/src/app.css b/vue-typography/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-typography/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-typography/src/components/editor/examples/typography/editor.vue b/vue-typography/src/components/editor/examples/typography/editor.vue new file mode 100644 index 0000000000..808b26ca30 --- /dev/null +++ b/vue-typography/src/components/editor/examples/typography/editor.vue @@ -0,0 +1,38 @@ + + + diff --git a/vue-typography/src/components/editor/examples/typography/extension.ts b/vue-typography/src/components/editor/examples/typography/extension.ts new file mode 100644 index 0000000000..2ffac09de1 --- /dev/null +++ b/vue-typography/src/components/editor/examples/typography/extension.ts @@ -0,0 +1,17 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMath } from 'prosekit/extensions/math' + +import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex' + +export function defineExtension() { + return union( + defineBasicExtension(), + defineMath({ + renderMathBlock: renderKaTeXMathBlock, + renderMathInline: renderKaTeXMathInline, + }), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-typography/src/components/editor/examples/typography/index.ts b/vue-typography/src/components/editor/examples/typography/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-typography/src/components/editor/examples/typography/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-typography/src/components/editor/sample/katex.ts b/vue-typography/src/components/editor/sample/katex.ts new file mode 100644 index 0000000000..0f759617cd --- /dev/null +++ b/vue-typography/src/components/editor/sample/katex.ts @@ -0,0 +1,17 @@ +import { render } from 'katex' + +export function renderKaTeXMathBlock(text: string, element: HTMLElement) { + render(text, element, { + displayMode: true, + throwOnError: false, + output: 'mathml', + }) +} + +export function renderKaTeXMathInline(text: string, element: HTMLElement) { + render(text, element, { + displayMode: false, + throwOnError: false, + output: 'mathml', + }) +} diff --git a/vue-typography/src/components/editor/sample/sample-doc-typography.ts b/vue-typography/src/components/editor/sample/sample-doc-typography.ts new file mode 100644 index 0000000000..db18b8155c --- /dev/null +++ b/vue-typography/src/components/editor/sample/sample-doc-typography.ts @@ -0,0 +1,693 @@ +import type { NodeJSON } from 'prosekit/core' + +const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0` + +const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` + +const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}` + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'ProseKit Typography', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This example shows the typography styles provided by ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'prosekit/basic/typography.css', + }, + { + type: 'text', + text: '.', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Inline marks', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Text can be formatted in different ways: ', + }, + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'bold text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'italic', + }, + ], + text: 'italic text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'underlined text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'strike', + }, + ], + text: 'strikethrough text', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'code', + }, + ], + text: 'inline code', + }, + { + type: 'text', + text: ', ', + }, + { + type: 'text', + marks: [ + { + type: 'link', + attrs: { + href: 'https://example.com', + target: null, + rel: null, + }, + }, + ], + text: 'links', + }, + { + type: 'text', + text: ',', + }, + { + type: 'hardBreak', + }, + { + type: 'text', + text: 'and hard breaks (Shift+Enter).', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Headings', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 1, + }, + content: [ + { + type: 'text', + text: 'Heading 1', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Heading 2', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 3, + }, + content: [ + { + type: 'text', + text: 'Heading 3', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 4, + }, + content: [ + { + type: 'text', + text: 'Heading 4', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 5, + }, + content: [ + { + type: 'text', + text: 'Heading 5', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 6, + }, + content: [ + { + type: 'text', + text: 'Heading 6', + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Lists', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Here are different types of lists:', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 1', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Unordered list item 2', + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item A', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'bullet', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Nested item B', + }, + ], + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'First ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'ordered', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Second ordered item', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: true, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Completed task', + }, + ], + }, + ], + }, + { + type: 'list', + attrs: { + kind: 'task', + order: null, + checked: false, + collapsed: false, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Pending task', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Blockquotes', + }, + ], + }, + { + type: 'blockquote', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is a blockquote demonstrating how quoted content appears in the editor. It can span multiple lines and maintains proper formatting.', + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Code Blocks', + }, + ], + }, + { + type: 'codeBlock', + attrs: { + language: '', + }, + content: [ + { + type: 'text', + text: "function example() {\n const greeting = 'Hello ProseKit!';\n console.log(greeting);\n return greeting;\n}", + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Horizontal Rule', + }, + ], + }, + { + type: 'horizontalRule', + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Images', + }, + ], + }, + { + type: 'image', + attrs: { + src: 'https://static.photos/blurred/640x360/42', + }, + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Tables', + }, + ], + }, + { + type: 'table', + content: [ + { + type: 'tableRow', + content: [ + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 1', + }, + ], + }, + ], + }, + { + type: 'tableHeaderCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Header 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 1', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 2', + }, + ], + }, + ], + }, + ], + }, + { + type: 'tableRow', + content: [ + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 3', + }, + ], + }, + ], + }, + { + type: 'tableCell', + attrs: { + colspan: 1, + rowspan: 1, + colwidth: null, + }, + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Cell 4', + }, + ], + }, + ], + }, + ], + }, + ], + }, + { + type: 'heading', + attrs: { + level: 2, + }, + content: [ + { + type: 'text', + text: 'Math', + }, + ], + }, + { + type: 'paragraph', + content: [ + { type: 'text', text: "Inline math like Euler's identity " }, + { + type: 'mathInline', + content: [{ type: 'text', text: EULER_IDENTITY }], + }, + { type: 'text', text: ' and the quadratic formula ' }, + { + type: 'mathInline', + content: [{ type: 'text', text: QUADRATIC_FORMULA }], + }, + { type: 'text', text: ' can appear within text.' }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Block-level equations are displayed on their own line:', + }, + ], + }, + { + type: 'mathBlock', + content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }], + }, + ], +} diff --git a/vue-typography/src/components/editor/ui/block-handle/block-handle.vue b/vue-typography/src/components/editor/ui/block-handle/block-handle.vue new file mode 100644 index 0000000000..ba06a1416a --- /dev/null +++ b/vue-typography/src/components/editor/ui/block-handle/block-handle.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue-typography/src/components/editor/ui/block-handle/index.ts b/vue-typography/src/components/editor/ui/block-handle/index.ts new file mode 100644 index 0000000000..2c33eb5726 --- /dev/null +++ b/vue-typography/src/components/editor/ui/block-handle/index.ts @@ -0,0 +1 @@ +export { default as BlockHandle } from './block-handle.vue' diff --git a/vue-typography/src/components/editor/ui/drop-indicator/drop-indicator.vue b/vue-typography/src/components/editor/ui/drop-indicator/drop-indicator.vue new file mode 100644 index 0000000000..cac51a8629 --- /dev/null +++ b/vue-typography/src/components/editor/ui/drop-indicator/drop-indicator.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-typography/src/components/editor/ui/drop-indicator/index.ts b/vue-typography/src/components/editor/ui/drop-indicator/index.ts new file mode 100644 index 0000000000..b455b1217b --- /dev/null +++ b/vue-typography/src/components/editor/ui/drop-indicator/index.ts @@ -0,0 +1 @@ +export { default as DropIndicator } from './drop-indicator.vue' diff --git a/vue-typography/src/main.ts b/vue-typography/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-typography/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-typography/tsconfig.app.json b/vue-typography/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-typography/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-typography/tsconfig.json b/vue-typography/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-typography/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-typography/tsconfig.node.json b/vue-typography/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-typography/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-typography/vite.config.ts b/vue-typography/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-typography/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-underline/.gitignore b/vue-underline/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-underline/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-underline/README.md b/vue-underline/README.md new file mode 100644 index 0000000000..ba351a9a3e --- /dev/null +++ b/vue-underline/README.md @@ -0,0 +1,15 @@ +# vue-underline + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-underline) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-underline) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-underline vue-underline +cd vue-underline +npm install +npm run dev +``` diff --git a/vue-underline/index.html b/vue-underline/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-underline/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-underline/package.json b/vue-underline/package.json new file mode 100644 index 0000000000..931694ad77 --- /dev/null +++ b/vue-underline/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-underline", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-underline/src/App.vue b/vue-underline/src/App.vue new file mode 100644 index 0000000000..ecb7590ff1 --- /dev/null +++ b/vue-underline/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-underline/src/app.css b/vue-underline/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-underline/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-underline/src/components/editor/examples/underline/editor.vue b/vue-underline/src/components/editor/examples/underline/editor.vue new file mode 100644 index 0000000000..7a0bc4bcc4 --- /dev/null +++ b/vue-underline/src/components/editor/examples/underline/editor.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-underline/src/components/editor/examples/underline/extension.ts b/vue-underline/src/components/editor/examples/underline/extension.ts new file mode 100644 index 0000000000..16a9b58284 --- /dev/null +++ b/vue-underline/src/components/editor/examples/underline/extension.ts @@ -0,0 +1,17 @@ +import { defineBaseKeymap, union } from 'prosekit/core' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' + +export function defineExtension() { + return union( + defineBaseKeymap(), + defineDoc(), + defineText(), + defineParagraph(), + defineUnderline(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-underline/src/components/editor/examples/underline/index.ts b/vue-underline/src/components/editor/examples/underline/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-underline/src/components/editor/examples/underline/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-underline/src/components/editor/sample/sample-doc-underline.ts b/vue-underline/src/components/editor/sample/sample-doc-underline.ts new file mode 100644 index 0000000000..6af561064b --- /dev/null +++ b/vue-underline/src/components/editor/sample/sample-doc-underline.ts @@ -0,0 +1,30 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + marks: [ + { + type: 'underline', + }, + ], + text: 'This is underline', + }, + ], + }, + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'This is normal text', + }, + ], + }, + ], +} diff --git a/vue-underline/src/components/editor/ui/button/button.vue b/vue-underline/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-underline/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-underline/src/components/editor/ui/button/index.ts b/vue-underline/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-underline/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-underline/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-underline/src/components/editor/ui/image-upload-popover/index.ts b/vue-underline/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-underline/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-underline/src/components/editor/ui/toolbar/index.ts b/vue-underline/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-underline/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-underline/src/components/editor/ui/toolbar/toolbar.vue b/vue-underline/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-underline/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-underline/src/main.ts b/vue-underline/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-underline/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-underline/tsconfig.app.json b/vue-underline/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-underline/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-underline/tsconfig.json b/vue-underline/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-underline/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-underline/tsconfig.node.json b/vue-underline/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-underline/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-underline/vite.config.ts b/vue-underline/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-underline/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-unmount/.gitignore b/vue-unmount/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-unmount/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-unmount/README.md b/vue-unmount/README.md new file mode 100644 index 0000000000..d746f5a982 --- /dev/null +++ b/vue-unmount/README.md @@ -0,0 +1,15 @@ +# vue-unmount + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-unmount) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-unmount) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-unmount vue-unmount +cd vue-unmount +npm install +npm run dev +``` diff --git a/vue-unmount/index.html b/vue-unmount/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-unmount/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-unmount/package.json b/vue-unmount/package.json new file mode 100644 index 0000000000..18e7d1fe62 --- /dev/null +++ b/vue-unmount/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-unmount", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-unmount/src/App.vue b/vue-unmount/src/App.vue new file mode 100644 index 0000000000..9975aabaee --- /dev/null +++ b/vue-unmount/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-unmount/src/app.css b/vue-unmount/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-unmount/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-unmount/src/components/editor/examples/unmount/editor-component.vue b/vue-unmount/src/components/editor/examples/unmount/editor-component.vue new file mode 100644 index 0000000000..78f726342d --- /dev/null +++ b/vue-unmount/src/components/editor/examples/unmount/editor-component.vue @@ -0,0 +1,36 @@ + + + diff --git a/vue-unmount/src/components/editor/examples/unmount/editor.vue b/vue-unmount/src/components/editor/examples/unmount/editor.vue new file mode 100644 index 0000000000..5f3d19b635 --- /dev/null +++ b/vue-unmount/src/components/editor/examples/unmount/editor.vue @@ -0,0 +1,37 @@ + + + diff --git a/vue-unmount/src/components/editor/examples/unmount/extension-component.vue b/vue-unmount/src/components/editor/examples/unmount/extension-component.vue new file mode 100644 index 0000000000..4204dbb234 --- /dev/null +++ b/vue-unmount/src/components/editor/examples/unmount/extension-component.vue @@ -0,0 +1,19 @@ + + + diff --git a/vue-unmount/src/components/editor/examples/unmount/index.ts b/vue-unmount/src/components/editor/examples/unmount/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-unmount/src/components/editor/examples/unmount/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-unmount/src/components/editor/ui/button/button.vue b/vue-unmount/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-unmount/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-unmount/src/components/editor/ui/button/index.ts b/vue-unmount/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-unmount/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-unmount/src/components/editor/ui/inline-menu/index.ts b/vue-unmount/src/components/editor/ui/inline-menu/index.ts new file mode 100644 index 0000000000..8c72e460c8 --- /dev/null +++ b/vue-unmount/src/components/editor/ui/inline-menu/index.ts @@ -0,0 +1 @@ +export { default as InlineMenu } from './inline-menu.vue' diff --git a/vue-unmount/src/components/editor/ui/inline-menu/inline-menu.vue b/vue-unmount/src/components/editor/ui/inline-menu/inline-menu.vue new file mode 100644 index 0000000000..cacb76b189 --- /dev/null +++ b/vue-unmount/src/components/editor/ui/inline-menu/inline-menu.vue @@ -0,0 +1,219 @@ + + + diff --git a/vue-unmount/src/main.ts b/vue-unmount/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-unmount/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-unmount/tsconfig.app.json b/vue-unmount/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-unmount/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-unmount/tsconfig.json b/vue-unmount/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-unmount/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-unmount/tsconfig.node.json b/vue-unmount/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-unmount/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-unmount/vite.config.ts b/vue-unmount/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-unmount/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-user-menu-dynamic/.gitignore b/vue-user-menu-dynamic/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-user-menu-dynamic/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-user-menu-dynamic/README.md b/vue-user-menu-dynamic/README.md new file mode 100644 index 0000000000..e8b8509188 --- /dev/null +++ b/vue-user-menu-dynamic/README.md @@ -0,0 +1,15 @@ +# vue-user-menu-dynamic + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-user-menu-dynamic) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-user-menu-dynamic) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-user-menu-dynamic vue-user-menu-dynamic +cd vue-user-menu-dynamic +npm install +npm run dev +``` diff --git a/vue-user-menu-dynamic/index.html b/vue-user-menu-dynamic/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-user-menu-dynamic/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-user-menu-dynamic/package.json b/vue-user-menu-dynamic/package.json new file mode 100644 index 0000000000..075133939f --- /dev/null +++ b/vue-user-menu-dynamic/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-user-menu-dynamic", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-user-menu-dynamic/src/App.vue b/vue-user-menu-dynamic/src/App.vue new file mode 100644 index 0000000000..854c270518 --- /dev/null +++ b/vue-user-menu-dynamic/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-user-menu-dynamic/src/app.css b/vue-user-menu-dynamic/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-user-menu-dynamic/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.vue b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.vue new file mode 100644 index 0000000000..b645dccef1 --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/editor.vue @@ -0,0 +1,29 @@ + + + diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts new file mode 100644 index 0000000000..ff2c40b104 --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts new file mode 100644 index 0000000000..5c7f71008f --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/use-user-query.ts @@ -0,0 +1,34 @@ +import type { Ref } from 'vue' +import { ref, watchEffect } from 'vue' + +import { queryUsers, type User } from '../../sample/sample-query-users' + +/** + * Simulate a user searching with some delay. + */ +export function useUserQuery(query: Ref, enabled: Ref) { + const users = ref([]) + const loading = ref(true) + + watchEffect((onCleanup) => { + if (!enabled.value) { + users.value = [] + return + } + + loading.value = true + let cancelled = false + void queryUsers(query.value).then((result) => { + if (cancelled) { + return + } + users.value = result + loading.value = false + }) + onCleanup(() => { + cancelled = true + }) + }) + + return { loading, users } +} diff --git a/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.vue b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.vue new file mode 100644 index 0000000000..388dd6ebff --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/examples/user-menu-dynamic/user-menu-dynamic.vue @@ -0,0 +1,29 @@ + + + diff --git a/vue-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts b/vue-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts new file mode 100644 index 0000000000..ab78fd5525 --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/sample/sample-query-users.ts @@ -0,0 +1,40 @@ +import { users } from './sample-user-data' + +export interface User { + id: number + name: string +} + +const connectHandlers: VoidFunction[] = [] +let networkStatus: 'fast' | 'slow' | 'offline' = 'slow' + +/** + * A utility function to simulate different network states. Useful for testing. + * + * @internal + */ +export function simulateNetworkStatus(status: 'fast' | 'slow' | 'offline') { + networkStatus = status + if (status !== 'offline') { + connectHandlers.forEach((handler) => handler()) + connectHandlers.length = 0 + } +} + +/** + * Simulate a user searching with some delay. + */ +export async function queryUsers(query: string): Promise { + if (networkStatus === 'offline') { + await new Promise((resolve) => connectHandlers.push(resolve)) + } + if (networkStatus === 'slow') { + await new Promise((resolve) => setTimeout(resolve, 300)) + } + + const normalizedQuery = query.toLowerCase().trim() + const filteredUsers = users + .filter((user) => user.name.toLowerCase().includes(normalizedQuery)) + .slice(0, 10) + return filteredUsers +} diff --git a/vue-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts b/vue-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/vue-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts b/vue-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..29fde1b0b4 --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu.vue' diff --git a/vue-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.vue b/vue-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.vue new file mode 100644 index 0000000000..60b4c3131c --- /dev/null +++ b/vue-user-menu-dynamic/src/components/editor/ui/user-menu/user-menu.vue @@ -0,0 +1,74 @@ + + + diff --git a/vue-user-menu-dynamic/src/main.ts b/vue-user-menu-dynamic/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-user-menu-dynamic/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-user-menu-dynamic/tsconfig.app.json b/vue-user-menu-dynamic/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-user-menu-dynamic/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-user-menu-dynamic/tsconfig.json b/vue-user-menu-dynamic/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-user-menu-dynamic/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-user-menu-dynamic/tsconfig.node.json b/vue-user-menu-dynamic/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-user-menu-dynamic/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-user-menu-dynamic/vite.config.ts b/vue-user-menu-dynamic/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-user-menu-dynamic/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-user-menu/.gitignore b/vue-user-menu/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-user-menu/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-user-menu/README.md b/vue-user-menu/README.md new file mode 100644 index 0000000000..27cb75bd33 --- /dev/null +++ b/vue-user-menu/README.md @@ -0,0 +1,15 @@ +# vue-user-menu + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-user-menu) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-user-menu) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-user-menu vue-user-menu +cd vue-user-menu +npm install +npm run dev +``` diff --git a/vue-user-menu/index.html b/vue-user-menu/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-user-menu/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-user-menu/package.json b/vue-user-menu/package.json new file mode 100644 index 0000000000..eebbb81638 --- /dev/null +++ b/vue-user-menu/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-user-menu", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-user-menu/src/App.vue b/vue-user-menu/src/App.vue new file mode 100644 index 0000000000..161d909b5d --- /dev/null +++ b/vue-user-menu/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-user-menu/src/app.css b/vue-user-menu/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-user-menu/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-user-menu/src/components/editor/examples/user-menu/editor.vue b/vue-user-menu/src/components/editor/examples/user-menu/editor.vue new file mode 100644 index 0000000000..6f45da5a5b --- /dev/null +++ b/vue-user-menu/src/components/editor/examples/user-menu/editor.vue @@ -0,0 +1,34 @@ + + + diff --git a/vue-user-menu/src/components/editor/examples/user-menu/extension.ts b/vue-user-menu/src/components/editor/examples/user-menu/extension.ts new file mode 100644 index 0000000000..56a97a4779 --- /dev/null +++ b/vue-user-menu/src/components/editor/examples/user-menu/extension.ts @@ -0,0 +1,16 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' +import { defineMention } from 'prosekit/extensions/mention' +import { definePlaceholder } from 'prosekit/extensions/placeholder' + +export function defineExtension() { + return union( + defineBasicExtension(), + definePlaceholder({ + placeholder: 'Type @ to mention someone or # to tag something...', + }), + defineMention(), + ) +} + +export type EditorExtension = ReturnType diff --git a/vue-user-menu/src/components/editor/examples/user-menu/index.ts b/vue-user-menu/src/components/editor/examples/user-menu/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-user-menu/src/components/editor/examples/user-menu/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-user-menu/src/components/editor/sample/sample-tag-data.ts b/vue-user-menu/src/components/editor/sample/sample-tag-data.ts new file mode 100644 index 0000000000..391cfd4ff4 --- /dev/null +++ b/vue-user-menu/src/components/editor/sample/sample-tag-data.ts @@ -0,0 +1,12 @@ +export const tags = [ + { id: 1, label: 'book' }, + { id: 2, label: 'movie' }, + { id: 3, label: 'trip' }, + { id: 4, label: 'music' }, + { id: 5, label: 'art' }, + { id: 6, label: 'food' }, + { id: 7, label: 'sport' }, + { id: 8, label: 'technology' }, + { id: 9, label: 'fashion' }, + { id: 10, label: 'nature' }, +] diff --git a/vue-user-menu/src/components/editor/sample/sample-user-data.ts b/vue-user-menu/src/components/editor/sample/sample-user-data.ts new file mode 100644 index 0000000000..2a90c86c32 --- /dev/null +++ b/vue-user-menu/src/components/editor/sample/sample-user-data.ts @@ -0,0 +1,54 @@ +export const users = [ + { id: 1, name: 'Alex' }, + { id: 2, name: 'Alice' }, + { id: 3, name: 'Ben' }, + { id: 4, name: 'Bob' }, + { id: 5, name: 'Charlie' }, + { id: 6, name: 'Cara' }, + { id: 7, name: 'Derek' }, + { id: 8, name: 'Diana' }, + { id: 9, name: 'Ethan' }, + { id: 10, name: 'Eva' }, + { id: 11, name: 'Frank' }, + { id: 12, name: 'Fiona' }, + { id: 13, name: 'George' }, + { id: 14, name: 'Gina' }, + { id: 15, name: 'Harry' }, + { id: 16, name: 'Hannah' }, + { id: 17, name: 'Ivan' }, + { id: 18, name: 'Iris' }, + { id: 19, name: 'Jack' }, + { id: 20, name: 'Jasmine' }, + { id: 21, name: 'Kevin' }, + { id: 22, name: 'Kate' }, + { id: 23, name: 'Leo' }, + { id: 24, name: 'Lily' }, + { id: 25, name: 'Mike' }, + { id: 26, name: 'Mia' }, + { id: 27, name: 'Nathan' }, + { id: 28, name: 'Nancy' }, + { id: 29, name: 'Oscar' }, + { id: 30, name: 'Olivia' }, + { id: 31, name: 'Paul' }, + { id: 32, name: 'Penny' }, + { id: 33, name: 'Quentin' }, + { id: 34, name: 'Queen' }, + { id: 35, name: 'Roger' }, + { id: 36, name: 'Rita' }, + { id: 37, name: 'Sam' }, + { id: 38, name: 'Sara' }, + { id: 39, name: 'Tom' }, + { id: 40, name: 'Tina' }, + { id: 41, name: 'Ulysses' }, + { id: 42, name: 'Una' }, + { id: 43, name: 'Victor' }, + { id: 44, name: 'Vera' }, + { id: 45, name: 'Walter' }, + { id: 46, name: 'Wendy' }, + { id: 47, name: 'Xavier' }, + { id: 48, name: 'Xena' }, + { id: 49, name: 'Yan' }, + { id: 50, name: 'Yvonne' }, + { id: 51, name: 'Zack' }, + { id: 52, name: 'Zara' }, +] diff --git a/vue-user-menu/src/components/editor/ui/tag-menu/index.ts b/vue-user-menu/src/components/editor/ui/tag-menu/index.ts new file mode 100644 index 0000000000..6cb07b1d1c --- /dev/null +++ b/vue-user-menu/src/components/editor/ui/tag-menu/index.ts @@ -0,0 +1 @@ +export { default as TagMenu } from './tag-menu.vue' diff --git a/vue-user-menu/src/components/editor/ui/tag-menu/tag-menu.vue b/vue-user-menu/src/components/editor/ui/tag-menu/tag-menu.vue new file mode 100644 index 0000000000..a8928c53a9 --- /dev/null +++ b/vue-user-menu/src/components/editor/ui/tag-menu/tag-menu.vue @@ -0,0 +1,59 @@ + + + diff --git a/vue-user-menu/src/components/editor/ui/user-menu/index.ts b/vue-user-menu/src/components/editor/ui/user-menu/index.ts new file mode 100644 index 0000000000..29fde1b0b4 --- /dev/null +++ b/vue-user-menu/src/components/editor/ui/user-menu/index.ts @@ -0,0 +1 @@ +export { default as UserMenu } from './user-menu.vue' diff --git a/vue-user-menu/src/components/editor/ui/user-menu/user-menu.vue b/vue-user-menu/src/components/editor/ui/user-menu/user-menu.vue new file mode 100644 index 0000000000..60b4c3131c --- /dev/null +++ b/vue-user-menu/src/components/editor/ui/user-menu/user-menu.vue @@ -0,0 +1,74 @@ + + + diff --git a/vue-user-menu/src/main.ts b/vue-user-menu/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-user-menu/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-user-menu/tsconfig.app.json b/vue-user-menu/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-user-menu/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-user-menu/tsconfig.json b/vue-user-menu/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-user-menu/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-user-menu/tsconfig.node.json b/vue-user-menu/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-user-menu/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-user-menu/vite.config.ts b/vue-user-menu/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-user-menu/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-word-counter/.gitignore b/vue-word-counter/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-word-counter/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-word-counter/README.md b/vue-word-counter/README.md new file mode 100644 index 0000000000..9d90b288ee --- /dev/null +++ b/vue-word-counter/README.md @@ -0,0 +1,15 @@ +# vue-word-counter + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-word-counter) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-word-counter) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-word-counter vue-word-counter +cd vue-word-counter +npm install +npm run dev +``` diff --git a/vue-word-counter/index.html b/vue-word-counter/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-word-counter/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-word-counter/package.json b/vue-word-counter/package.json new file mode 100644 index 0000000000..f0ac5c9bbf --- /dev/null +++ b/vue-word-counter/package.json @@ -0,0 +1,27 @@ +{ + "name": "example-vue-word-counter", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-word-counter/src/App.vue b/vue-word-counter/src/App.vue new file mode 100644 index 0000000000..473e418f95 --- /dev/null +++ b/vue-word-counter/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-word-counter/src/app.css b/vue-word-counter/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-word-counter/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-word-counter/src/components/editor/examples/word-counter/editor.vue b/vue-word-counter/src/components/editor/examples/word-counter/editor.vue new file mode 100644 index 0000000000..3146088eed --- /dev/null +++ b/vue-word-counter/src/components/editor/examples/word-counter/editor.vue @@ -0,0 +1,39 @@ + + + diff --git a/vue-word-counter/src/components/editor/examples/word-counter/extension.ts b/vue-word-counter/src/components/editor/examples/word-counter/extension.ts new file mode 100644 index 0000000000..1c2b5cbd74 --- /dev/null +++ b/vue-word-counter/src/components/editor/examples/word-counter/extension.ts @@ -0,0 +1,8 @@ +import { defineBasicExtension } from 'prosekit/basic' +import { union } from 'prosekit/core' + +export function defineExtension() { + return union(defineBasicExtension()) +} + +export type EditorExtension = ReturnType diff --git a/vue-word-counter/src/components/editor/examples/word-counter/index.ts b/vue-word-counter/src/components/editor/examples/word-counter/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-word-counter/src/components/editor/examples/word-counter/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-word-counter/src/components/editor/sample/sample-doc-word-counter.ts b/vue-word-counter/src/components/editor/sample/sample-doc-word-counter.ts new file mode 100644 index 0000000000..0b5d435038 --- /dev/null +++ b/vue-word-counter/src/components/editor/sample/sample-doc-word-counter.ts @@ -0,0 +1,16 @@ +import type { NodeJSON } from 'prosekit/core' + +export const sampleContent: NodeJSON = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Start typing and observe the word count update below.', + }, + ], + }, + ], +} diff --git a/vue-word-counter/src/components/editor/ui/word-counter/index.ts b/vue-word-counter/src/components/editor/ui/word-counter/index.ts new file mode 100644 index 0000000000..596748a07a --- /dev/null +++ b/vue-word-counter/src/components/editor/ui/word-counter/index.ts @@ -0,0 +1 @@ +export { default as WordCounter } from './word-counter.vue' diff --git a/vue-word-counter/src/components/editor/ui/word-counter/word-counter.vue b/vue-word-counter/src/components/editor/ui/word-counter/word-counter.vue new file mode 100644 index 0000000000..39c3566ad3 --- /dev/null +++ b/vue-word-counter/src/components/editor/ui/word-counter/word-counter.vue @@ -0,0 +1,22 @@ + + + diff --git a/vue-word-counter/src/main.ts b/vue-word-counter/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-word-counter/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-word-counter/tsconfig.app.json b/vue-word-counter/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-word-counter/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-word-counter/tsconfig.json b/vue-word-counter/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-word-counter/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-word-counter/tsconfig.node.json b/vue-word-counter/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-word-counter/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-word-counter/vite.config.ts b/vue-word-counter/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-word-counter/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) diff --git a/vue-yjs/.gitignore b/vue-yjs/.gitignore new file mode 100644 index 0000000000..5d6225c6df --- /dev/null +++ b/vue-yjs/.gitignore @@ -0,0 +1,4 @@ +node_modules +dist +.next +.svelte-kit diff --git a/vue-yjs/README.md b/vue-yjs/README.md new file mode 100644 index 0000000000..a5b407f183 --- /dev/null +++ b/vue-yjs/README.md @@ -0,0 +1,15 @@ +# vue-yjs + +A [ProseKit](https://prosekit.dev) example. + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/prosekit/examples/tree/master/vue-yjs) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/prosekit/examples/tree/master/vue-yjs) + +Run the example locally with: + +```bash +npx degit prosekit/examples/vue-yjs vue-yjs +cd vue-yjs +npm install +npm run dev +``` diff --git a/vue-yjs/index.html b/vue-yjs/index.html new file mode 100644 index 0000000000..d8952bb9e6 --- /dev/null +++ b/vue-yjs/index.html @@ -0,0 +1,12 @@ + + + + + + ProseKit + Vue + + +
+ + + diff --git a/vue-yjs/package.json b/vue-yjs/package.json new file mode 100644 index 0000000000..28c806b6a3 --- /dev/null +++ b/vue-yjs/package.json @@ -0,0 +1,30 @@ +{ + "name": "example-vue-yjs", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "vue-tsc -b && vite build", + "dev": "vite", + "preview": "vite preview" + }, + "dependencies": { + "prosekit": "^0.21.0", + "vue": "^3.5.34", + "y-prosemirror": "^1.3.7", + "y-websocket": "^3.0.0", + "yjs": "^13.6.30" + }, + "devDependencies": { + "@egoist/tailwindcss-icons": "^1.9.2", + "@iconify-json/lucide": "^1.2.107", + "@tailwindcss/vite": "^4.3.0", + "@types/node": "^24.12.4", + "@vitejs/plugin-vue": "^6.0.6", + "@vue/tsconfig": "^0.9.1", + "tailwindcss": "^4.3.0", + "typescript": "^6.0.3", + "vite": "^8.0.13", + "vue-tsc": "^3.2.8" + } +} diff --git a/vue-yjs/src/App.vue b/vue-yjs/src/App.vue new file mode 100644 index 0000000000..b40ec3b400 --- /dev/null +++ b/vue-yjs/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/vue-yjs/src/app.css b/vue-yjs/src/app.css new file mode 100644 index 0000000000..ccad1aefaa --- /dev/null +++ b/vue-yjs/src/app.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +@plugin "@egoist/tailwindcss-icons"; + +body { + height: 100svh; + display: grid; + max-width: 900px; + padding: 16px; + margin-left: auto; + margin-right: auto; +} diff --git a/vue-yjs/src/components/editor/examples/yjs/editor-component.vue b/vue-yjs/src/components/editor/examples/yjs/editor-component.vue new file mode 100644 index 0000000000..b0dae528b3 --- /dev/null +++ b/vue-yjs/src/components/editor/examples/yjs/editor-component.vue @@ -0,0 +1,38 @@ + + + diff --git a/vue-yjs/src/components/editor/examples/yjs/editor.vue b/vue-yjs/src/components/editor/examples/yjs/editor.vue new file mode 100644 index 0000000000..f0f9ea0c44 --- /dev/null +++ b/vue-yjs/src/components/editor/examples/yjs/editor.vue @@ -0,0 +1,23 @@ + + + diff --git a/vue-yjs/src/components/editor/examples/yjs/extension.ts b/vue-yjs/src/components/editor/examples/yjs/extension.ts new file mode 100644 index 0000000000..f1a581932b --- /dev/null +++ b/vue-yjs/src/components/editor/examples/yjs/extension.ts @@ -0,0 +1,48 @@ +import { defineBaseCommands, defineBaseKeymap, union } from 'prosekit/core' +import { defineBlockquote } from 'prosekit/extensions/blockquote' +import { defineBold } from 'prosekit/extensions/bold' +import { defineCode } from 'prosekit/extensions/code' +import { defineDoc } from 'prosekit/extensions/doc' +import { defineDropCursor } from 'prosekit/extensions/drop-cursor' +import { defineHeading } from 'prosekit/extensions/heading' +import { defineImage } from 'prosekit/extensions/image' +import { defineItalic } from 'prosekit/extensions/italic' +import { defineLink } from 'prosekit/extensions/link' +import { defineList } from 'prosekit/extensions/list' +import { defineModClickPrevention } from 'prosekit/extensions/mod-click-prevention' +import { defineParagraph } from 'prosekit/extensions/paragraph' +import { defineStrike } from 'prosekit/extensions/strike' +import { defineTable } from 'prosekit/extensions/table' +import { defineText } from 'prosekit/extensions/text' +import { defineUnderline } from 'prosekit/extensions/underline' +import { defineVirtualSelection } from 'prosekit/extensions/virtual-selection' +import { defineYjs } from 'prosekit/extensions/yjs' +import type { Awareness } from 'prosekit/extensions/yjs' +import type * as Y from 'yjs' + +export function defineExtension(doc: Y.Doc, awareness: Awareness) { + return union([ + defineDoc(), + defineText(), + defineHeading(), + defineList(), + defineBlockquote(), + defineBaseKeymap(), + defineBaseCommands(), + defineItalic(), + defineBold(), + defineUnderline(), + defineStrike(), + defineCode(), + defineLink(), + defineImage(), + defineParagraph(), + defineDropCursor(), + defineVirtualSelection(), + defineModClickPrevention(), + defineTable(), + defineYjs({ doc, awareness }), + ]) +} + +export type EditorExtension = ReturnType diff --git a/vue-yjs/src/components/editor/examples/yjs/index.ts b/vue-yjs/src/components/editor/examples/yjs/index.ts new file mode 100644 index 0000000000..dcc4cb6219 --- /dev/null +++ b/vue-yjs/src/components/editor/examples/yjs/index.ts @@ -0,0 +1 @@ +export { default as ExampleEditor } from './editor.vue' diff --git a/vue-yjs/src/components/editor/ui/button/button.vue b/vue-yjs/src/components/editor/ui/button/button.vue new file mode 100644 index 0000000000..bfe2720904 --- /dev/null +++ b/vue-yjs/src/components/editor/ui/button/button.vue @@ -0,0 +1,42 @@ + + + diff --git a/vue-yjs/src/components/editor/ui/button/index.ts b/vue-yjs/src/components/editor/ui/button/index.ts new file mode 100644 index 0000000000..06b26c2d74 --- /dev/null +++ b/vue-yjs/src/components/editor/ui/button/index.ts @@ -0,0 +1 @@ +export { default as Button } from './button.vue' diff --git a/vue-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.vue b/vue-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.vue new file mode 100644 index 0000000000..da2eee95c5 --- /dev/null +++ b/vue-yjs/src/components/editor/ui/image-upload-popover/image-upload-popover.vue @@ -0,0 +1,139 @@ + + + diff --git a/vue-yjs/src/components/editor/ui/image-upload-popover/index.ts b/vue-yjs/src/components/editor/ui/image-upload-popover/index.ts new file mode 100644 index 0000000000..ec7600958a --- /dev/null +++ b/vue-yjs/src/components/editor/ui/image-upload-popover/index.ts @@ -0,0 +1 @@ +export { default as ImageUploadPopover } from './image-upload-popover.vue' diff --git a/vue-yjs/src/components/editor/ui/toolbar/index.ts b/vue-yjs/src/components/editor/ui/toolbar/index.ts new file mode 100644 index 0000000000..d4ee621292 --- /dev/null +++ b/vue-yjs/src/components/editor/ui/toolbar/index.ts @@ -0,0 +1 @@ +export { default as Toolbar } from './toolbar.vue' diff --git a/vue-yjs/src/components/editor/ui/toolbar/toolbar.vue b/vue-yjs/src/components/editor/ui/toolbar/toolbar.vue new file mode 100644 index 0000000000..9faacc0316 --- /dev/null +++ b/vue-yjs/src/components/editor/ui/toolbar/toolbar.vue @@ -0,0 +1,347 @@ + + + diff --git a/vue-yjs/src/main.ts b/vue-yjs/src/main.ts new file mode 100644 index 0000000000..0ed1fdfef8 --- /dev/null +++ b/vue-yjs/src/main.ts @@ -0,0 +1,5 @@ +import './app.css' +import { createApp } from 'vue' +import App from './App.vue' + +createApp(App).mount('#app') diff --git a/vue-yjs/tsconfig.app.json b/vue-yjs/tsconfig.app.json new file mode 100644 index 0000000000..7c0e5ef3a8 --- /dev/null +++ b/vue-yjs/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/vue-yjs/tsconfig.json b/vue-yjs/tsconfig.json new file mode 100644 index 0000000000..1ffef600d9 --- /dev/null +++ b/vue-yjs/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/vue-yjs/tsconfig.node.json b/vue-yjs/tsconfig.node.json new file mode 100644 index 0000000000..8a67f62f4c --- /dev/null +++ b/vue-yjs/tsconfig.node.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vue-yjs/vite.config.ts b/vue-yjs/vite.config.ts new file mode 100644 index 0000000000..2e9084402d --- /dev/null +++ b/vue-yjs/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import tailwindcss from '@tailwindcss/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), tailwindcss()], +}) From 92083074ff94148734cd62576e2f8ed48d39af66 Mon Sep 17 00:00:00 2001 From: ocavue Date: Sun, 17 May 2026 05:12:39 +1000 Subject: [PATCH 3/3] update svelte --- .templates/template-svelte/package.json | 2 +- svelte-block-handle/package.json | 2 +- svelte-blockquote/package.json | 2 +- svelte-bold/package.json | 2 +- svelte-change-tracking/package.json | 2 +- svelte-code-block-themes/package.json | 2 +- svelte-code-block/package.json | 2 +- svelte-code/package.json | 2 +- svelte-drop-cursor/package.json | 2 +- svelte-emoji-rules/package.json | 2 +- svelte-full/package.json | 2 +- svelte-gap-cursor/package.json | 2 +- svelte-hard-break/package.json | 2 +- svelte-heading/package.json | 2 +- svelte-highlight/package.json | 2 +- svelte-horizontal-rule/package.json | 2 +- svelte-image-view/package.json | 2 +- svelte-inline-menu/package.json | 2 +- svelte-italic/package.json | 2 +- svelte-katex/package.json | 2 +- svelte-keymap/package.json | 2 +- svelte-link-mark-view/package.json | 2 +- svelte-link/package.json | 2 +- svelte-list-custom-checkbox/package.json | 2 +- svelte-list/package.json | 2 +- svelte-loro/package.json | 2 +- svelte-mark-rule/package.json | 2 +- svelte-minimal/package.json | 2 +- svelte-page/package.json | 2 +- svelte-placeholder/package.json | 2 +- svelte-readonly/package.json | 2 +- svelte-rtl/package.json | 2 +- svelte-save-html/package.json | 2 +- svelte-save-json/package.json | 2 +- svelte-save-markdown/package.json | 2 +- svelte-search/package.json | 2 +- svelte-slash-menu/package.json | 2 +- svelte-strike/package.json | 2 +- svelte-sub-sup/package.json | 2 +- svelte-table/package.json | 2 +- svelte-text-align/package.json | 2 +- svelte-text-color/package.json | 2 +- svelte-toolbar/package.json | 2 +- svelte-typography/package.json | 2 +- svelte-underline/package.json | 2 +- svelte-unmount/package.json | 2 +- svelte-user-menu-dynamic/package.json | 2 +- svelte-user-menu/package.json | 2 +- svelte-word-counter/package.json | 2 +- svelte-yjs/package.json | 2 +- 50 files changed, 50 insertions(+), 50 deletions(-) diff --git a/.templates/template-svelte/package.json b/.templates/template-svelte/package.json index 38286406b8..c6d746b173 100644 --- a/.templates/template-svelte/package.json +++ b/.templates/template-svelte/package.json @@ -16,7 +16,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-block-handle/package.json b/svelte-block-handle/package.json index 3c732dd7bd..e3cadcf8a1 100644 --- a/svelte-block-handle/package.json +++ b/svelte-block-handle/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-blockquote/package.json b/svelte-blockquote/package.json index 1b2fc18838..aca51e3efd 100644 --- a/svelte-blockquote/package.json +++ b/svelte-blockquote/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-bold/package.json b/svelte-bold/package.json index 7c6bd584f0..7dff1a5f3f 100644 --- a/svelte-bold/package.json +++ b/svelte-bold/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-change-tracking/package.json b/svelte-change-tracking/package.json index 6e55f1b1a7..3649a10146 100644 --- a/svelte-change-tracking/package.json +++ b/svelte-change-tracking/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-code-block-themes/package.json b/svelte-code-block-themes/package.json index 55fccc1765..f4fd35ba41 100644 --- a/svelte-code-block-themes/package.json +++ b/svelte-code-block-themes/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-code-block/package.json b/svelte-code-block/package.json index c37e5df28e..ef5a708265 100644 --- a/svelte-code-block/package.json +++ b/svelte-code-block/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-code/package.json b/svelte-code/package.json index 85b82ecb3d..e6016529f2 100644 --- a/svelte-code/package.json +++ b/svelte-code/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-drop-cursor/package.json b/svelte-drop-cursor/package.json index 087738bb00..f88cfbadf2 100644 --- a/svelte-drop-cursor/package.json +++ b/svelte-drop-cursor/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-emoji-rules/package.json b/svelte-emoji-rules/package.json index e1a5d6e854..e572857f33 100644 --- a/svelte-emoji-rules/package.json +++ b/svelte-emoji-rules/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-full/package.json b/svelte-full/package.json index f2a3bd21be..1703409d9e 100644 --- a/svelte-full/package.json +++ b/svelte-full/package.json @@ -19,7 +19,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-gap-cursor/package.json b/svelte-gap-cursor/package.json index b96f7026b0..58f93a4810 100644 --- a/svelte-gap-cursor/package.json +++ b/svelte-gap-cursor/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-hard-break/package.json b/svelte-hard-break/package.json index 80611d0502..0af4fba623 100644 --- a/svelte-hard-break/package.json +++ b/svelte-hard-break/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-heading/package.json b/svelte-heading/package.json index cd1f9cef1b..7004299727 100644 --- a/svelte-heading/package.json +++ b/svelte-heading/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-highlight/package.json b/svelte-highlight/package.json index d5d0161644..97fe2b7f83 100644 --- a/svelte-highlight/package.json +++ b/svelte-highlight/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-horizontal-rule/package.json b/svelte-horizontal-rule/package.json index 45acb8f3cd..71556d431b 100644 --- a/svelte-horizontal-rule/package.json +++ b/svelte-horizontal-rule/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-image-view/package.json b/svelte-image-view/package.json index fb8dd1c8c8..88499c0dd3 100644 --- a/svelte-image-view/package.json +++ b/svelte-image-view/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-inline-menu/package.json b/svelte-inline-menu/package.json index 709502a18d..4da47264bb 100644 --- a/svelte-inline-menu/package.json +++ b/svelte-inline-menu/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-italic/package.json b/svelte-italic/package.json index 6498231129..d95e3c4ae4 100644 --- a/svelte-italic/package.json +++ b/svelte-italic/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-katex/package.json b/svelte-katex/package.json index 17a605a9c0..9825cbb964 100644 --- a/svelte-katex/package.json +++ b/svelte-katex/package.json @@ -19,7 +19,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-keymap/package.json b/svelte-keymap/package.json index b3d9d56c55..3118f30d13 100644 --- a/svelte-keymap/package.json +++ b/svelte-keymap/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-link-mark-view/package.json b/svelte-link-mark-view/package.json index ae839bbd8f..e22c81bf85 100644 --- a/svelte-link-mark-view/package.json +++ b/svelte-link-mark-view/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-link/package.json b/svelte-link/package.json index 834b75a5c3..6db5d4fd39 100644 --- a/svelte-link/package.json +++ b/svelte-link/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-list-custom-checkbox/package.json b/svelte-list-custom-checkbox/package.json index 6b6dc48675..72e6946775 100644 --- a/svelte-list-custom-checkbox/package.json +++ b/svelte-list-custom-checkbox/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-list/package.json b/svelte-list/package.json index 3da32eeb9a..30b01a2ef6 100644 --- a/svelte-list/package.json +++ b/svelte-list/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-loro/package.json b/svelte-loro/package.json index efc88ab0d5..87ac5ac4ad 100644 --- a/svelte-loro/package.json +++ b/svelte-loro/package.json @@ -20,7 +20,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-mark-rule/package.json b/svelte-mark-rule/package.json index 72b9ea835a..7bab92ccff 100644 --- a/svelte-mark-rule/package.json +++ b/svelte-mark-rule/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-minimal/package.json b/svelte-minimal/package.json index fed18d28d8..926aa495b8 100644 --- a/svelte-minimal/package.json +++ b/svelte-minimal/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-page/package.json b/svelte-page/package.json index dd67b1d8ac..48a1b4b2bc 100644 --- a/svelte-page/package.json +++ b/svelte-page/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-placeholder/package.json b/svelte-placeholder/package.json index 7c577ac9f3..616909d3cc 100644 --- a/svelte-placeholder/package.json +++ b/svelte-placeholder/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-readonly/package.json b/svelte-readonly/package.json index 12d586da2e..2c5e0e5fee 100644 --- a/svelte-readonly/package.json +++ b/svelte-readonly/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-rtl/package.json b/svelte-rtl/package.json index f5ab0ade68..8a20110c06 100644 --- a/svelte-rtl/package.json +++ b/svelte-rtl/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-save-html/package.json b/svelte-save-html/package.json index 97b0b99961..4092bd0530 100644 --- a/svelte-save-html/package.json +++ b/svelte-save-html/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-save-json/package.json b/svelte-save-json/package.json index c75b6ba56d..7513eeb4a9 100644 --- a/svelte-save-json/package.json +++ b/svelte-save-json/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-save-markdown/package.json b/svelte-save-markdown/package.json index e051af2402..139486c273 100644 --- a/svelte-save-markdown/package.json +++ b/svelte-save-markdown/package.json @@ -25,7 +25,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-search/package.json b/svelte-search/package.json index 7fa6f2caba..8014ed31e9 100644 --- a/svelte-search/package.json +++ b/svelte-search/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-slash-menu/package.json b/svelte-slash-menu/package.json index 51a939eb16..8a6d27571d 100644 --- a/svelte-slash-menu/package.json +++ b/svelte-slash-menu/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-strike/package.json b/svelte-strike/package.json index 9e2c6c2944..d32ce34c2f 100644 --- a/svelte-strike/package.json +++ b/svelte-strike/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-sub-sup/package.json b/svelte-sub-sup/package.json index a98803cfab..cd59327565 100644 --- a/svelte-sub-sup/package.json +++ b/svelte-sub-sup/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-table/package.json b/svelte-table/package.json index 657a17ea78..c151d237af 100644 --- a/svelte-table/package.json +++ b/svelte-table/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-text-align/package.json b/svelte-text-align/package.json index 2babe2dc9e..f1fb1a6ce6 100644 --- a/svelte-text-align/package.json +++ b/svelte-text-align/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-text-color/package.json b/svelte-text-color/package.json index 81fc87b906..37a4671e3e 100644 --- a/svelte-text-color/package.json +++ b/svelte-text-color/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-toolbar/package.json b/svelte-toolbar/package.json index 79bd3d8969..02166da851 100644 --- a/svelte-toolbar/package.json +++ b/svelte-toolbar/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-typography/package.json b/svelte-typography/package.json index 5a268ad1c0..3dcae206db 100644 --- a/svelte-typography/package.json +++ b/svelte-typography/package.json @@ -19,7 +19,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-underline/package.json b/svelte-underline/package.json index bfc6b78805..f4a2992e0c 100644 --- a/svelte-underline/package.json +++ b/svelte-underline/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-unmount/package.json b/svelte-unmount/package.json index d29de2d2df..d69b69c2df 100644 --- a/svelte-unmount/package.json +++ b/svelte-unmount/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-user-menu-dynamic/package.json b/svelte-user-menu-dynamic/package.json index a039119d3a..1507ecc442 100644 --- a/svelte-user-menu-dynamic/package.json +++ b/svelte-user-menu-dynamic/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-user-menu/package.json b/svelte-user-menu/package.json index 9c80e624de..2c205f468a 100644 --- a/svelte-user-menu/package.json +++ b/svelte-user-menu/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-word-counter/package.json b/svelte-word-counter/package.json index 63f672d51b..2c1132e698 100644 --- a/svelte-word-counter/package.json +++ b/svelte-word-counter/package.json @@ -18,7 +18,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1", diff --git a/svelte-yjs/package.json b/svelte-yjs/package.json index 7d91c55513..20c75aca55 100644 --- a/svelte-yjs/package.json +++ b/svelte-yjs/package.json @@ -21,7 +21,7 @@ "@tailwindcss/vite": "^4.3.0", "@tsconfig/svelte": "^5.0.8", "postcss": "^8.5.14", - "svelte": "5.55.7", + "svelte": "^5.55.7", "svelte-check": "^4.4.8", "tailwindcss": "^4.3.0", "tslib": "^2.8.1",